Skip to content

Commit

Permalink
HHH-8893 HBM transform/mock
Browse files Browse the repository at this point in the history
  • Loading branch information
brmeyer committed May 21, 2014
1 parent 047d308 commit 754af46
Show file tree
Hide file tree
Showing 49 changed files with 1,055 additions and 173 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.annotations;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import org.hibernate.metamodel.source.internal.jaxb.hbm.HbmXmlTransformer;

/**
* Can be used to mark an association as the inverse side, without explicitly identifying the "mappedBy" on the
* association annotation itself. This solely exists for transforming HBM to JPA (see {@link HbmXmlTransformer}).
* Direct use should be completely avoided.
*
* @author Brett Meyer
*
* @deprecated Use {@link OneToOne#mappedBy()}, {@link OneToMany#mappedBy()}, or {@link ManyToMany#mappedBy()}.
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Deprecated
public @interface Inverse {

/**
* Primarily used to carry a M2M inverse side's <key>.
*
* @return hbmKey
*/
String hbmKey();
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.Arrays;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

Expand Down Expand Up @@ -807,4 +808,12 @@ public static String makePath(String base, String name) {
public static String nullIfEmpty(String value) {
return isEmpty( value ) ? null : value;
}

public static boolean containsIgnoreCase(List<String> list, String s) {
s = toLowerCase( s );
for (int i = 0; i < list.size(); i++) {
list.set( i, toLowerCase( list.get( i ) ) );
}
return list.contains( s );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@

import org.hibernate.AssertionFailure;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.source.internal.annotations.RootEntitySourceImpl;
import org.hibernate.metamodel.source.spi.AggregatedCompositeIdentifierSource;
import org.hibernate.metamodel.source.spi.AttributeSource;
import org.hibernate.metamodel.source.spi.AttributeSourceResolutionContext;
import org.hibernate.metamodel.source.spi.ColumnSource;
import org.hibernate.metamodel.source.spi.EmbeddedAttributeSource;
import org.hibernate.metamodel.source.spi.EntityHierarchySource;
import org.hibernate.metamodel.source.spi.EntitySource;
Expand All @@ -46,6 +49,8 @@
import org.hibernate.metamodel.source.spi.NonAggregatedCompositeIdentifierSource;
import org.hibernate.metamodel.source.spi.PluralAttributeIndexSourceResolver;
import org.hibernate.metamodel.source.spi.PluralAttributeSource;
import org.hibernate.metamodel.source.spi.RelationalValueSource;
import org.hibernate.metamodel.source.spi.RelationalValueSourceContainer;
import org.hibernate.metamodel.source.spi.SimpleIdentifierSource;
import org.hibernate.metamodel.source.spi.SingularAttributeSource;
import org.hibernate.metamodel.source.spi.ToOneAttributeSource;
Expand All @@ -55,7 +60,6 @@
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.relational.Column;

import org.jboss.logging.Logger;

/**
Expand Down Expand Up @@ -357,6 +361,10 @@ public void indexPluralAttributeSource(PluralAttributeSource attributeSource) {
);
}
}

public EntitySource entitySource(String entityName) {
return entitySourceIndexByEntityName.get( entityName ).entitySource;
}

private static class EntitySourceIndex implements AttributeIndexingTarget {
private final SourceIndex sourceIndex;
Expand Down Expand Up @@ -489,7 +497,7 @@ public void resolveAttributeSources(BinderLocalBindingContext context) {

// Resolve plural attributes.
for ( PluralAttributeSource pluralAttributeSource : inversePluralAttributeSourcesByKey.values() ) {
if ( pluralAttributeSource.getMappedBy() != null ) {
if ( pluralAttributeSource.isInverse() ) {
// This plural attribute is mappedBy the opposite side of the association,
// so it needs to be resolved.
pluralAttributeSource.resolvePluralAttributeElementSource( sourceResolutionContext );
Expand Down Expand Up @@ -565,6 +573,78 @@ public AttributeSource resolveAttributeSource(String entityName, String attribut
public List<Column> resolveIdentifierColumns() {
return context.locateBinding( entitySource ).getPrimaryTable().getPrimaryKey().getColumns();
}

@Override
public String resolveAttributeName(String entityName, List<String> columnNames) {
final EntitySource entitySource = sourceIndex.entitySource( entityName );
for (AttributeSource attributeSource : entitySource.attributeSources()) {
final String owningAttributeName = resolveAttributeName( attributeSource, entityName, columnNames );
if (! StringHelper.isEmpty( owningAttributeName )) {
return owningAttributeName;
}
}

// TODO: yuck
if (RootEntitySourceImpl.class.isInstance( entitySource )) {
final RootEntitySourceImpl rootSource = (RootEntitySourceImpl) entitySource;
for (AttributeSource attributeSource : rootSource.getIdentifierAttributes()) {
final String owningAttributeName = resolveAttributeName( attributeSource, entityName, columnNames );
if (! StringHelper.isEmpty( owningAttributeName )) {
return owningAttributeName;
}
}
}
return null;
}

private String resolveAttributeName(AttributeSource attributeSource, String entityName, List<String> columnNames) {
if (EmbeddedAttributeSource.class.isInstance( attributeSource )) {
final EmbeddedAttributeSource embeddedSource = (EmbeddedAttributeSource) attributeSource;
for (AttributeSource embeddedAttributeSource : embeddedSource.getEmbeddableSource().attributeSources()) {
final String owningAttributeName = resolveAttributeName( embeddedAttributeSource, entityName, columnNames );
if (! StringHelper.isEmpty( owningAttributeName )) {
return embeddedSource.getName() + "." + owningAttributeName;
}
}
}
else if (SingularAttributeSource.class.isInstance( attributeSource )) {
final SingularAttributeSource singularSource = (SingularAttributeSource) attributeSource;
int count = 0;
for (RelationalValueSource relationalSource : singularSource.relationalValueSources()) {
if (ColumnSource.class.isInstance( relationalSource )) {
final ColumnSource columnSource = (ColumnSource) relationalSource;
if (StringHelper.containsIgnoreCase( columnNames, columnSource.getName() )) {
count++;
}
}
}
if (count == columnNames.size()
&& singularSource.relationalValueSources().size() == columnNames.size()) {
return attributeSource.getName();
}
}
else if (PluralAttributeSource.class.isInstance( attributeSource )) {
final PluralAttributeSource pluralSource = (PluralAttributeSource) attributeSource;
if (pluralSource.getElementSource() instanceof RelationalValueSourceContainer) {
final RelationalValueSourceContainer relationalSourceContainer
= (RelationalValueSourceContainer) pluralSource.getElementSource();
int count = 0;
for (RelationalValueSource relationalSource : relationalSourceContainer.relationalValueSources()) {
if (ColumnSource.class.isInstance( relationalSource )) {
final ColumnSource columnSource = (ColumnSource) relationalSource;
if (StringHelper.containsIgnoreCase( columnNames, columnSource.getName() )) {
count++;
}
}
}
if (count == columnNames.size()
&& pluralSource.getPluralAttribute().getJoinColumnValues().size() == columnNames.size()) {
return attributeSource.getName();
}
}
}
return null;
}
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public AnnotationInstance findTypeAnnotation(DotName annotationType) {

@Override
public AnnotationInstance findLocalTypeAnnotation(DotName annotationType) {
return typeAnnotationMap.get( annotationType );
return typeAnnotationMap == null ? null : typeAnnotationMap.get( annotationType );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor;
import org.hibernate.metamodel.source.internal.annotations.attribute.PersistentAttribute;
import org.hibernate.metamodel.source.internal.annotations.attribute.PluralAttributeElementDetails;
import org.hibernate.metamodel.source.spi.HibernateTypeSource;
import org.hibernate.metamodel.source.spi.JavaTypeDescriptorResolvable;

Expand Down Expand Up @@ -62,6 +63,26 @@ public HibernateTypeSourceImpl(String name) {
this.parameters = Collections.emptyMap();
}

public HibernateTypeSourceImpl(final PluralAttributeElementDetails element) {
this.nameHolder = new ValueHolder<String>(
new ValueHolder.DeferredInitializer<String>() {
@Override
public String initialize() {
return element.getTypeResolver().getExplicitHibernateTypeName();
}
}
);
this.parameterHolder = new ValueHolder<Map<String, String>>(
new ValueHolder.DeferredInitializer<Map<String, String>>() {
@Override
public Map<String, String> initialize() {
return element.getTypeResolver().getExplicitHibernateTypeParameters();
}
}
);
this.javaType = element.getJavaType();
}

@Override
public String getName() {
return name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public PluralAttributeElementSourceBasicImpl(PluralAttributeSourceImpl pluralAtt

@Override
public HibernateTypeSource getExplicitHibernateTypeSource() {
return new HibernateTypeSourceImpl( getPluralAttribute() );
return new HibernateTypeSourceImpl( getPluralAttribute().getElementDetails() );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public boolean createForeignKeyConstraint() {

@Override
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
if ( attribute.getMappedByAttributeName() != null ) {
if ( attribute.isInverse() ) {
throw new IllegalStateException( "Cannot determine foreign key information because association is not the owner." );
}
for ( Column joinColumn : attribute.getJoinColumnValues() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
import org.hibernate.metamodel.spi.PluralAttributeNature;
import org.hibernate.metamodel.spi.binding.Caching;
import org.hibernate.metamodel.spi.binding.CustomSQL;

import org.jboss.jandex.AnnotationInstance;

/**
Expand Down Expand Up @@ -104,7 +103,7 @@ public PluralAttributeSourceImpl(
this.typeSource = new HibernateTypeSourceImpl( pluralAttribute );


if ( pluralAttribute.getMappedByAttributeName() == null ) {
if ( ! pluralAttribute.isInverse() ) {
this.ownerAttributeSource = this;
this.elementSource = determineElementSource( this, this );
}
Expand Down Expand Up @@ -182,6 +181,7 @@ public PersistentAttribute getAnnotatedAttribute() {
return getPluralAttribute();
}

@Override
public PluralAttribute getPluralAttribute() {
return pluralAttribute;
}
Expand All @@ -197,9 +197,6 @@ public PluralAttributeNature getNature() {

@Override
public PluralAttributeElementSource getElementSource() {
if ( elementSource == null ) {
throw new IllegalStateException( "elementSource has not been initialized yet." );
}
return elementSource;
}

Expand All @@ -215,7 +212,7 @@ public int getBatchSize() {

@Override
public boolean usesJoinTable() {
if ( pluralAttribute.getMappedByAttributeName() != null ) {
if ( pluralAttribute.isInverse() ) {
throw new IllegalStateException( "Cannot determine if a join table is used because plural attribute is not the owner." );
}
// By default, a unidirectional one-to-many (i.e., with mappedBy == null) uses a join table,
Expand Down Expand Up @@ -253,7 +250,7 @@ private static PluralAttributeElementSource determineElementSource(
return new PluralAttributeElementSourceEmbeddedImpl( pluralAttributeSource );
}
case MANY_TO_MANY: {
if ( associationAttribute.getMappedByAttributeName() == null ) {
if ( ! associationAttribute.isInverse() ) {
return new PluralAttributeElementSourceAssociationManyToManyImpl( pluralAttributeSource );
}
else {
Expand All @@ -266,15 +263,15 @@ private static PluralAttributeElementSource determineElementSource(
: ( (PluralAttributeSource) ownerAttributeSource ).usesJoinTable();

if ( usesJoinTable ) {
if ( associationAttribute.getMappedByAttributeName() == null ) {
if ( ! associationAttribute.isInverse() ) {
return new PluralAttributeElementSourceAssociationManyToManyImpl( pluralAttributeSource );
}
else {
return new MappedByPluralAttributeElementSourceAssociationManyToManyImpl( pluralAttributeSource );
}
}
else {
if ( associationAttribute.getMappedByAttributeName() == null ) {
if ( ! associationAttribute.isInverse() ) {
return new PluralAttributeElementSourceAssociationOneToManyImpl( pluralAttributeSource );
}
else {
Expand All @@ -300,7 +297,7 @@ public PluralAttributeKeySource getKeySource() {
public TableSpecificationSource getCollectionTableSpecificationSource() {
// todo - see org.hibernate.metamodel.internal.Binder#bindOneToManyCollectionKey
// todo - needs to cater for @CollectionTable and @JoinTable
if ( pluralAttribute.getMappedByAttributeName() != null ) {
if ( pluralAttribute.isInverse() ) {
throw new IllegalStateException( "Cannot get collection table because this association is not the owner." );
}
final AnnotationInstance joinTableAnnotation = pluralAttribute.getJoinTableAnnotation();
Expand Down Expand Up @@ -343,7 +340,7 @@ public String getMappedBy() {

@Override
public boolean isInverse() {
return getMappedBy() != null;
return pluralAttribute.isInverse();
}

@Override
Expand Down Expand Up @@ -467,11 +464,27 @@ public PluralAttributeElementSource resolvePluralAttributeElementSource(Attribut
private void buildElementSource(AttributeSourceResolutionContext context) {
// elementSource has not been initialized, so we need to resolve it using the
// association owner.

if (StringHelper.isEmpty( pluralAttribute.getMappedByAttributeName() )) {
// The attribute is inverse, but no mappedBy given (ex: HBM XML transformation uses the temporary
// @Inverse annotation since it cannot reliably find the owning attribute on its own). Attempt to resolve
// using the join columns.
// TODO: Move elsewhere?
final JavaTypeDescriptor elementType = pluralAttribute.getElementDetails().getJavaType();
final List<String> joinColumnNames = new ArrayList<String>();
for (Column joinColumn : pluralAttribute.getJoinColumnValues()) {
joinColumnNames.add( joinColumn.getName() );
}
pluralAttribute.setMappedByAttributeName( context.resolveAttributeName(
elementType.getName().toString(), joinColumnNames ) );
}

// Get the owner attribute source that maps the opposite side of the association.
ownerAttributeSource = context.resolveAttributeSource(
pluralAttribute.getElementDetails().getJavaType().getName().toString(),
pluralAttribute.getMappedByAttributeName()
);

// Initialize resolved entitySource.
elementSource = determineElementSource( ownerAttributeSource, this );
if ( !MappedByAssociationSource.class.isInstance( elementSource ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
*/
public interface AssociationAttribute {
public String getMappedByAttributeName();
@Deprecated
public boolean isInverse();

public Set<CascadeType> getJpaCascadeTypes();
public Set<org.hibernate.annotations.CascadeType> getHibernateCascadeTypes();
Expand Down
Loading

0 comments on commit 754af46

Please sign in to comment.