Skip to content

Commit 754af46

Browse files
committed
HHH-8893 HBM transform/mock
1 parent 047d308 commit 754af46

File tree

49 files changed

+1055
-173
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1055
-173
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
5+
* indicated by the @author tags or express copyright attribution
6+
* statements applied by the authors. All third-party contributions are
7+
* distributed under license by Red Hat Inc.
8+
*
9+
* This copyrighted material is made available to anyone wishing to use, modify,
10+
* copy, or redistribute it subject to the terms and conditions of the GNU
11+
* Lesser General Public License, as published by the Free Software Foundation.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16+
* for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public License
19+
* along with this distribution; if not, write to:
20+
* Free Software Foundation, Inc.
21+
* 51 Franklin Street, Fifth Floor
22+
* Boston, MA 02110-1301 USA
23+
*/
24+
package org.hibernate.annotations;
25+
26+
import static java.lang.annotation.ElementType.FIELD;
27+
import static java.lang.annotation.ElementType.METHOD;
28+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
29+
30+
import java.lang.annotation.Retention;
31+
import java.lang.annotation.Target;
32+
33+
import javax.persistence.ManyToMany;
34+
import javax.persistence.OneToMany;
35+
import javax.persistence.OneToOne;
36+
37+
import org.hibernate.metamodel.source.internal.jaxb.hbm.HbmXmlTransformer;
38+
39+
/**
40+
* Can be used to mark an association as the inverse side, without explicitly identifying the "mappedBy" on the
41+
* association annotation itself. This solely exists for transforming HBM to JPA (see {@link HbmXmlTransformer}).
42+
* Direct use should be completely avoided.
43+
*
44+
* @author Brett Meyer
45+
*
46+
* @deprecated Use {@link OneToOne#mappedBy()}, {@link OneToMany#mappedBy()}, or {@link ManyToMany#mappedBy()}.
47+
*/
48+
@Target({METHOD, FIELD})
49+
@Retention(RUNTIME)
50+
@Deprecated
51+
public @interface Inverse {
52+
53+
/**
54+
* Primarily used to carry a M2M inverse side's <key>.
55+
*
56+
* @return hbmKey
57+
*/
58+
String hbmKey();
59+
}

hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Arrays;
3030
import java.util.BitSet;
3131
import java.util.Iterator;
32+
import java.util.List;
3233
import java.util.Locale;
3334
import java.util.StringTokenizer;
3435

@@ -807,4 +808,12 @@ public static String makePath(String base, String name) {
807808
public static String nullIfEmpty(String value) {
808809
return isEmpty( value ) ? null : value;
809810
}
811+
812+
public static boolean containsIgnoreCase(List<String> list, String s) {
813+
s = toLowerCase( s );
814+
for (int i = 0; i < list.size(); i++) {
815+
list.set( i, toLowerCase( list.get( i ) ) );
816+
}
817+
return list.contains( s );
818+
}
810819
}

hibernate-core/src/main/java/org/hibernate/metamodel/internal/binder/SourceIndex.java

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@
3434

3535
import org.hibernate.AssertionFailure;
3636
import org.hibernate.internal.CoreLogging;
37+
import org.hibernate.internal.util.StringHelper;
38+
import org.hibernate.metamodel.source.internal.annotations.RootEntitySourceImpl;
3739
import org.hibernate.metamodel.source.spi.AggregatedCompositeIdentifierSource;
3840
import org.hibernate.metamodel.source.spi.AttributeSource;
3941
import org.hibernate.metamodel.source.spi.AttributeSourceResolutionContext;
42+
import org.hibernate.metamodel.source.spi.ColumnSource;
4043
import org.hibernate.metamodel.source.spi.EmbeddedAttributeSource;
4144
import org.hibernate.metamodel.source.spi.EntityHierarchySource;
4245
import org.hibernate.metamodel.source.spi.EntitySource;
@@ -46,6 +49,8 @@
4649
import org.hibernate.metamodel.source.spi.NonAggregatedCompositeIdentifierSource;
4750
import org.hibernate.metamodel.source.spi.PluralAttributeIndexSourceResolver;
4851
import org.hibernate.metamodel.source.spi.PluralAttributeSource;
52+
import org.hibernate.metamodel.source.spi.RelationalValueSource;
53+
import org.hibernate.metamodel.source.spi.RelationalValueSourceContainer;
4954
import org.hibernate.metamodel.source.spi.SimpleIdentifierSource;
5055
import org.hibernate.metamodel.source.spi.SingularAttributeSource;
5156
import org.hibernate.metamodel.source.spi.ToOneAttributeSource;
@@ -55,7 +60,6 @@
5560
import org.hibernate.metamodel.spi.binding.AttributeBinding;
5661
import org.hibernate.metamodel.spi.binding.EntityBinding;
5762
import org.hibernate.metamodel.spi.relational.Column;
58-
5963
import org.jboss.logging.Logger;
6064

6165
/**
@@ -357,6 +361,10 @@ public void indexPluralAttributeSource(PluralAttributeSource attributeSource) {
357361
);
358362
}
359363
}
364+
365+
public EntitySource entitySource(String entityName) {
366+
return entitySourceIndexByEntityName.get( entityName ).entitySource;
367+
}
360368

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

490498
// Resolve plural attributes.
491499
for ( PluralAttributeSource pluralAttributeSource : inversePluralAttributeSourcesByKey.values() ) {
492-
if ( pluralAttributeSource.getMappedBy() != null ) {
500+
if ( pluralAttributeSource.isInverse() ) {
493501
// This plural attribute is mappedBy the opposite side of the association,
494502
// so it needs to be resolved.
495503
pluralAttributeSource.resolvePluralAttributeElementSource( sourceResolutionContext );
@@ -565,6 +573,78 @@ public AttributeSource resolveAttributeSource(String entityName, String attribut
565573
public List<Column> resolveIdentifierColumns() {
566574
return context.locateBinding( entitySource ).getPrimaryTable().getPrimaryKey().getColumns();
567575
}
576+
577+
@Override
578+
public String resolveAttributeName(String entityName, List<String> columnNames) {
579+
final EntitySource entitySource = sourceIndex.entitySource( entityName );
580+
for (AttributeSource attributeSource : entitySource.attributeSources()) {
581+
final String owningAttributeName = resolveAttributeName( attributeSource, entityName, columnNames );
582+
if (! StringHelper.isEmpty( owningAttributeName )) {
583+
return owningAttributeName;
584+
}
585+
}
586+
587+
// TODO: yuck
588+
if (RootEntitySourceImpl.class.isInstance( entitySource )) {
589+
final RootEntitySourceImpl rootSource = (RootEntitySourceImpl) entitySource;
590+
for (AttributeSource attributeSource : rootSource.getIdentifierAttributes()) {
591+
final String owningAttributeName = resolveAttributeName( attributeSource, entityName, columnNames );
592+
if (! StringHelper.isEmpty( owningAttributeName )) {
593+
return owningAttributeName;
594+
}
595+
}
596+
}
597+
return null;
598+
}
599+
600+
private String resolveAttributeName(AttributeSource attributeSource, String entityName, List<String> columnNames) {
601+
if (EmbeddedAttributeSource.class.isInstance( attributeSource )) {
602+
final EmbeddedAttributeSource embeddedSource = (EmbeddedAttributeSource) attributeSource;
603+
for (AttributeSource embeddedAttributeSource : embeddedSource.getEmbeddableSource().attributeSources()) {
604+
final String owningAttributeName = resolveAttributeName( embeddedAttributeSource, entityName, columnNames );
605+
if (! StringHelper.isEmpty( owningAttributeName )) {
606+
return embeddedSource.getName() + "." + owningAttributeName;
607+
}
608+
}
609+
}
610+
else if (SingularAttributeSource.class.isInstance( attributeSource )) {
611+
final SingularAttributeSource singularSource = (SingularAttributeSource) attributeSource;
612+
int count = 0;
613+
for (RelationalValueSource relationalSource : singularSource.relationalValueSources()) {
614+
if (ColumnSource.class.isInstance( relationalSource )) {
615+
final ColumnSource columnSource = (ColumnSource) relationalSource;
616+
if (StringHelper.containsIgnoreCase( columnNames, columnSource.getName() )) {
617+
count++;
618+
}
619+
}
620+
}
621+
if (count == columnNames.size()
622+
&& singularSource.relationalValueSources().size() == columnNames.size()) {
623+
return attributeSource.getName();
624+
}
625+
}
626+
else if (PluralAttributeSource.class.isInstance( attributeSource )) {
627+
final PluralAttributeSource pluralSource = (PluralAttributeSource) attributeSource;
628+
if (pluralSource.getElementSource() instanceof RelationalValueSourceContainer) {
629+
final RelationalValueSourceContainer relationalSourceContainer
630+
= (RelationalValueSourceContainer) pluralSource.getElementSource();
631+
int count = 0;
632+
for (RelationalValueSource relationalSource : relationalSourceContainer.relationalValueSources()) {
633+
if (ColumnSource.class.isInstance( relationalSource )) {
634+
final ColumnSource columnSource = (ColumnSource) relationalSource;
635+
if (StringHelper.containsIgnoreCase( columnNames, columnSource.getName() )) {
636+
count++;
637+
}
638+
}
639+
}
640+
if (count == columnNames.size()
641+
&& pluralSource.getPluralAttribute().getJoinColumnValues().size() == columnNames.size()) {
642+
return attributeSource.getName();
643+
}
644+
}
645+
}
646+
return null;
647+
}
568648
};
569649
}
570650
}

hibernate-core/src/main/java/org/hibernate/metamodel/reflite/internal/DynamicTypeDescriptorImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public AnnotationInstance findTypeAnnotation(DotName annotationType) {
167167

168168
@Override
169169
public AnnotationInstance findLocalTypeAnnotation(DotName annotationType) {
170-
return typeAnnotationMap.get( annotationType );
170+
return typeAnnotationMap == null ? null : typeAnnotationMap.get( annotationType );
171171
}
172172

173173
@Override

hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/HibernateTypeSourceImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.hibernate.metamodel.reflite.spi.JavaTypeDescriptor;
3030
import org.hibernate.metamodel.source.internal.annotations.attribute.PersistentAttribute;
31+
import org.hibernate.metamodel.source.internal.annotations.attribute.PluralAttributeElementDetails;
3132
import org.hibernate.metamodel.source.spi.HibernateTypeSource;
3233
import org.hibernate.metamodel.source.spi.JavaTypeDescriptorResolvable;
3334

@@ -62,6 +63,26 @@ public HibernateTypeSourceImpl(String name) {
6263
this.parameters = Collections.emptyMap();
6364
}
6465

66+
public HibernateTypeSourceImpl(final PluralAttributeElementDetails element) {
67+
this.nameHolder = new ValueHolder<String>(
68+
new ValueHolder.DeferredInitializer<String>() {
69+
@Override
70+
public String initialize() {
71+
return element.getTypeResolver().getExplicitHibernateTypeName();
72+
}
73+
}
74+
);
75+
this.parameterHolder = new ValueHolder<Map<String, String>>(
76+
new ValueHolder.DeferredInitializer<Map<String, String>>() {
77+
@Override
78+
public Map<String, String> initialize() {
79+
return element.getTypeResolver().getExplicitHibernateTypeParameters();
80+
}
81+
}
82+
);
83+
this.javaType = element.getJavaType();
84+
}
85+
6586
@Override
6687
public String getName() {
6788
return name;

hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeElementSourceBasicImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public PluralAttributeElementSourceBasicImpl(PluralAttributeSourceImpl pluralAtt
2525

2626
@Override
2727
public HibernateTypeSource getExplicitHibernateTypeSource() {
28-
return new HibernateTypeSourceImpl( getPluralAttribute() );
28+
return new HibernateTypeSourceImpl( getPluralAttribute().getElementDetails() );
2929
}
3030

3131
@Override

hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeKeySourceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public boolean createForeignKeyConstraint() {
8080

8181
@Override
8282
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
83-
if ( attribute.getMappedByAttributeName() != null ) {
83+
if ( attribute.isInverse() ) {
8484
throw new IllegalStateException( "Cannot determine foreign key information because association is not the owner." );
8585
}
8686
for ( Column joinColumn : attribute.getJoinColumnValues() ) {

hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/PluralAttributeSourceImpl.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
import org.hibernate.metamodel.spi.PluralAttributeNature;
6969
import org.hibernate.metamodel.spi.binding.Caching;
7070
import org.hibernate.metamodel.spi.binding.CustomSQL;
71-
7271
import org.jboss.jandex.AnnotationInstance;
7372

7473
/**
@@ -104,7 +103,7 @@ public PluralAttributeSourceImpl(
104103
this.typeSource = new HibernateTypeSourceImpl( pluralAttribute );
105104

106105

107-
if ( pluralAttribute.getMappedByAttributeName() == null ) {
106+
if ( ! pluralAttribute.isInverse() ) {
108107
this.ownerAttributeSource = this;
109108
this.elementSource = determineElementSource( this, this );
110109
}
@@ -182,6 +181,7 @@ public PersistentAttribute getAnnotatedAttribute() {
182181
return getPluralAttribute();
183182
}
184183

184+
@Override
185185
public PluralAttribute getPluralAttribute() {
186186
return pluralAttribute;
187187
}
@@ -197,9 +197,6 @@ public PluralAttributeNature getNature() {
197197

198198
@Override
199199
public PluralAttributeElementSource getElementSource() {
200-
if ( elementSource == null ) {
201-
throw new IllegalStateException( "elementSource has not been initialized yet." );
202-
}
203200
return elementSource;
204201
}
205202

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

216213
@Override
217214
public boolean usesJoinTable() {
218-
if ( pluralAttribute.getMappedByAttributeName() != null ) {
215+
if ( pluralAttribute.isInverse() ) {
219216
throw new IllegalStateException( "Cannot determine if a join table is used because plural attribute is not the owner." );
220217
}
221218
// By default, a unidirectional one-to-many (i.e., with mappedBy == null) uses a join table,
@@ -253,7 +250,7 @@ private static PluralAttributeElementSource determineElementSource(
253250
return new PluralAttributeElementSourceEmbeddedImpl( pluralAttributeSource );
254251
}
255252
case MANY_TO_MANY: {
256-
if ( associationAttribute.getMappedByAttributeName() == null ) {
253+
if ( ! associationAttribute.isInverse() ) {
257254
return new PluralAttributeElementSourceAssociationManyToManyImpl( pluralAttributeSource );
258255
}
259256
else {
@@ -266,15 +263,15 @@ private static PluralAttributeElementSource determineElementSource(
266263
: ( (PluralAttributeSource) ownerAttributeSource ).usesJoinTable();
267264

268265
if ( usesJoinTable ) {
269-
if ( associationAttribute.getMappedByAttributeName() == null ) {
266+
if ( ! associationAttribute.isInverse() ) {
270267
return new PluralAttributeElementSourceAssociationManyToManyImpl( pluralAttributeSource );
271268
}
272269
else {
273270
return new MappedByPluralAttributeElementSourceAssociationManyToManyImpl( pluralAttributeSource );
274271
}
275272
}
276273
else {
277-
if ( associationAttribute.getMappedByAttributeName() == null ) {
274+
if ( ! associationAttribute.isInverse() ) {
278275
return new PluralAttributeElementSourceAssociationOneToManyImpl( pluralAttributeSource );
279276
}
280277
else {
@@ -300,7 +297,7 @@ public PluralAttributeKeySource getKeySource() {
300297
public TableSpecificationSource getCollectionTableSpecificationSource() {
301298
// todo - see org.hibernate.metamodel.internal.Binder#bindOneToManyCollectionKey
302299
// todo - needs to cater for @CollectionTable and @JoinTable
303-
if ( pluralAttribute.getMappedByAttributeName() != null ) {
300+
if ( pluralAttribute.isInverse() ) {
304301
throw new IllegalStateException( "Cannot get collection table because this association is not the owner." );
305302
}
306303
final AnnotationInstance joinTableAnnotation = pluralAttribute.getJoinTableAnnotation();
@@ -343,7 +340,7 @@ public String getMappedBy() {
343340

344341
@Override
345342
public boolean isInverse() {
346-
return getMappedBy() != null;
343+
return pluralAttribute.isInverse();
347344
}
348345

349346
@Override
@@ -467,11 +464,27 @@ public PluralAttributeElementSource resolvePluralAttributeElementSource(Attribut
467464
private void buildElementSource(AttributeSourceResolutionContext context) {
468465
// elementSource has not been initialized, so we need to resolve it using the
469466
// association owner.
467+
468+
if (StringHelper.isEmpty( pluralAttribute.getMappedByAttributeName() )) {
469+
// The attribute is inverse, but no mappedBy given (ex: HBM XML transformation uses the temporary
470+
// @Inverse annotation since it cannot reliably find the owning attribute on its own). Attempt to resolve
471+
// using the join columns.
472+
// TODO: Move elsewhere?
473+
final JavaTypeDescriptor elementType = pluralAttribute.getElementDetails().getJavaType();
474+
final List<String> joinColumnNames = new ArrayList<String>();
475+
for (Column joinColumn : pluralAttribute.getJoinColumnValues()) {
476+
joinColumnNames.add( joinColumn.getName() );
477+
}
478+
pluralAttribute.setMappedByAttributeName( context.resolveAttributeName(
479+
elementType.getName().toString(), joinColumnNames ) );
480+
}
481+
470482
// Get the owner attribute source that maps the opposite side of the association.
471483
ownerAttributeSource = context.resolveAttributeSource(
472484
pluralAttribute.getElementDetails().getJavaType().getName().toString(),
473485
pluralAttribute.getMappedByAttributeName()
474486
);
487+
475488
// Initialize resolved entitySource.
476489
elementSource = determineElementSource( ownerAttributeSource, this );
477490
if ( !MappedByAssociationSource.class.isInstance( elementSource ) ) {

hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/annotations/attribute/AssociationAttribute.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
*/
3232
public interface AssociationAttribute {
3333
public String getMappedByAttributeName();
34+
@Deprecated
35+
public boolean isInverse();
3436

3537
public Set<CascadeType> getJpaCascadeTypes();
3638
public Set<org.hibernate.annotations.CascadeType> getHibernateCascadeTypes();

0 commit comments

Comments
 (0)