Skip to content

Commit 910ba3b

Browse files
committed
HHH-7843 : Add support for one-to-one to new metamodel
1 parent a54f750 commit 910ba3b

31 files changed

+1067
-415
lines changed

hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,8 @@ public static boolean isEmpty(Object[] objs){
152152
public static boolean isNotEmpty(Object[] objs){
153153
return !isEmpty( objs );
154154
}
155+
156+
public static <T> List<T> createEmptyList(Class<T> elementClass) {
157+
return Collections.emptyList();
158+
}
155159
}

hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java

Lines changed: 258 additions & 93 deletions
Large diffs are not rendered by default.

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
4747
import org.hibernate.metamodel.spi.source.RelationalValueSource;
4848
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
49+
import org.hibernate.type.ForeignKeyDirection;
4950

5051
/**
5152
* @author Hardy Ferentschik
@@ -66,12 +67,12 @@ public ToOneAttributeSourceImpl(AssociationAttribute associationAttribute) {
6667

6768
@Override
6869
public Nature getNature() {
69-
if ( MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute.getNature() ) ) {
70-
return Nature.ONE_TO_ONE;
71-
}
72-
else if ( MappedAttribute.Nature.MANY_TO_ONE.equals( associationAttribute.getNature() ) ) {
70+
if ( MappedAttribute.Nature.MANY_TO_ONE.equals( associationAttribute.getNature() ) ) {
7371
return Nature.MANY_TO_ONE;
7472
}
73+
else if ( MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute.getNature() ) ) {
74+
throw new UnsupportedOperationException( "One-to-one using annotations is not supported yet." );
75+
}
7576
else {
7677
throw new AssertionError(
7778
"Wrong attribute nature for toOne attribute: " + associationAttribute.getNature()
@@ -177,6 +178,13 @@ public String toString() {
177178
return sb.toString();
178179
}
179180

181+
@Override
182+
public ForeignKeyDirection getForeignKeyDirection() {
183+
return getNature() == Nature.ONE_TO_ONE && !associationAttribute.isOptional() ?
184+
ForeignKeyDirection.FROM_PARENT :
185+
ForeignKeyDirection.TO_PARENT;
186+
}
187+
180188
public class AnnotationJoinColumnResolutionDelegate
181189
implements ForeignKeyContributingSource.JoinColumnResolutionDelegate {
182190
private final String logicalJoinTableName;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public class AssociationAttribute extends MappedAttribute {
7777
private final boolean isOrphanRemoval;
7878
private final FetchStyle fetchStyle;
7979
private final boolean mapsId;
80+
private final boolean hasPrimaryKeyJoinColumn;
8081
private final String referencedIdAttributeName;
8182
private final List<Column> joinColumnValues;
8283
private final AnnotationInstance joinTableAnnotation;
@@ -130,6 +131,7 @@ public static AssociationAttribute createAssociationAttribute(
130131
this.fetchStyle = determineFetchStyle();
131132
this.referencedIdAttributeName = determineMapsId();
132133
this.mapsId = referencedIdAttributeName != null;
134+
this.hasPrimaryKeyJoinColumn = determineHasPrimaryKeyJoinColumn();
133135

134136
this.joinTableAnnotation = determineExplicitJoinTable( annotations );
135137
}
@@ -170,6 +172,10 @@ public boolean mapsId() {
170172
return mapsId;
171173
}
172174

175+
public boolean hasPrimaryKeyJoinColumn() {
176+
return hasPrimaryKeyJoinColumn;
177+
}
178+
173179
public List<Column> getJoinColumnValues() {
174180
return joinColumnValues;
175181
}
@@ -410,6 +416,12 @@ private String determineMapsId() {
410416
return JandexHelper.getValue( mapsIdAnnotation, "value", String.class );
411417
}
412418

419+
private boolean determineHasPrimaryKeyJoinColumn() {
420+
AnnotationInstance primaryKeyJoinColumnAnnotation = JandexHelper.getSingleAnnotation( annotations(), JPADotNames.PRIMARY_KEY_JOIN_COLUMN );
421+
AnnotationInstance primaryKeyJoinColumnsAnnotation = JandexHelper.getSingleAnnotation( annotations(), JPADotNames.PRIMARY_KEY_JOIN_COLUMNS );
422+
return primaryKeyJoinColumnAnnotation != null || primaryKeyJoinColumnsAnnotation != null;
423+
}
424+
413425
private List<Column> determineJoinColumnAnnotations(Map<DotName, List<AnnotationInstance>> annotations) {
414426
ArrayList<Column> joinColumns = new ArrayList<Column>();
415427

hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractComponentAttributeSourceImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,12 @@ protected AttributeSource buildAttributeSource(JaxbManyToOneElement attributeEle
113113
}
114114

115115
protected AttributeSource buildAttributeSource(JaxbOneToOneElement attributeElement) {
116-
// todo : implement
117-
throw new NotYetImplementedException();
116+
return new OneToOneAttributeSourceImpl(
117+
sourceMappingDocument(),
118+
attributeElement,
119+
logicalTableName,
120+
naturalIdMutability
121+
);
118122
}
119123

120124
protected AttributeSource buildAttributeSource(JaxbAnyElement attributeElement) {

hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractEntitySourceImpl.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,16 @@ protected void processOneToOneAttributes(List<AttributeSource> results,
214214
List<JaxbOneToOneElement> elements,
215215
String logicalTableName,
216216
SingularAttributeBinding.NaturalIdMutability naturalIdMutability) {
217-
// todo : implement
217+
for ( JaxbOneToOneElement element : elements ) {
218+
results.add(
219+
new OneToOneAttributeSourceImpl(
220+
sourceMappingDocument(),
221+
element,
222+
logicalTableName,
223+
naturalIdMutability
224+
)
225+
);
226+
}
218227
}
219228

220229
protected void processAnyAttributes(List<AttributeSource> results,
@@ -288,9 +297,9 @@ protected void processBagAttributes(List<AttributeSource> results,
288297

289298

290299
private Set<SecondaryTableSource> buildSecondaryTables() {
291-
//if ( ! JoinElementSource.class.isInstance( entityElement ) ) {
292-
// return Collections.emptySet();
293-
//}
300+
if ( ! JoinElementSource.class.isInstance( entityElement ) ) {
301+
return Collections.emptySet();
302+
}
294303

295304
final Set<SecondaryTableSource> secondaryTableSources = new HashSet<SecondaryTableSource>();
296305
for ( JaxbJoinElement joinElement : ( (JoinElementSource) entityElement ).getJoin() ) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* Copyright (c) 2012, 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.metamodel.internal.source.hbm;
25+
26+
import java.util.ArrayList;
27+
import java.util.List;
28+
29+
import org.hibernate.engine.FetchStyle;
30+
import org.hibernate.engine.FetchTiming;
31+
import org.hibernate.mapping.PropertyGeneration;
32+
import org.hibernate.metamodel.internal.Binder;
33+
import org.hibernate.metamodel.spi.binding.AttributeBinding;
34+
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
35+
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
36+
import org.hibernate.metamodel.spi.relational.Value;
37+
import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource;
38+
import org.hibernate.metamodel.spi.source.MappingException;
39+
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
40+
41+
/**
42+
* @author Gail Badner
43+
*/
44+
public abstract class AbstractToOneAttributeSourceImpl extends AbstractHbmSourceNode implements ToOneAttributeSource{
45+
private final SingularAttributeBinding.NaturalIdMutability naturalIdMutability;
46+
private final String propertyRef;
47+
48+
AbstractToOneAttributeSourceImpl(
49+
MappingDocument sourceMappingDocument,
50+
SingularAttributeBinding.NaturalIdMutability naturalIdMutability,
51+
String propertyRef) {
52+
super( sourceMappingDocument );
53+
this.naturalIdMutability = naturalIdMutability;
54+
this.propertyRef = propertyRef;
55+
56+
}
57+
@Override
58+
public ExplicitHibernateTypeSource getTypeInformation() {
59+
return Helper.TO_ONE_ATTRIBUTE_TYPE_SOURCE;
60+
}
61+
62+
@Override
63+
public SingularAttributeBinding.NaturalIdMutability getNaturalIdMutability() {
64+
return naturalIdMutability;
65+
}
66+
67+
@Override
68+
public boolean isSingular() {
69+
return true;
70+
}
71+
72+
@Override
73+
public boolean isVirtualAttribute() {
74+
return false;
75+
}
76+
77+
@Override
78+
public PropertyGeneration getGeneration() {
79+
return PropertyGeneration.NEVER;
80+
}
81+
82+
@Override
83+
public boolean isLazy() {
84+
return getFetchTiming() != FetchTiming.IMMEDIATE;
85+
}
86+
87+
protected abstract String getFetchSelectionString();
88+
protected abstract String getLazySelectionString();
89+
protected abstract String getOuterJoinSelectionString();
90+
91+
@Override
92+
public boolean isUnWrapProxy() {
93+
final String lazySelection = getLazySelectionString();
94+
return lazySelection != null && lazySelection.equals( "no-proxy" );
95+
}
96+
97+
@Override
98+
public FetchTiming getFetchTiming() {
99+
final String lazySelection = getLazySelectionString();
100+
101+
if ( lazySelection == null ) {
102+
if ( "join".equals( getFetchSelectionString() ) || "true".equals( getOuterJoinSelectionString() ) ) {
103+
return FetchTiming.IMMEDIATE;
104+
}
105+
else if ( "false".equals( getOuterJoinSelectionString() ) ) {
106+
return FetchTiming.DELAYED;
107+
}
108+
else {
109+
return bindingContext().getMappingDefaults().areAssociationsLazy()
110+
? FetchTiming.DELAYED
111+
: FetchTiming.IMMEDIATE;
112+
}
113+
}
114+
else if ( "extra".equals( lazySelection ) ) {
115+
return FetchTiming.EXTRA_DELAYED;
116+
}
117+
else if ( "true".equals( lazySelection ) || "proxy".equals( lazySelection ) ) {
118+
return FetchTiming.DELAYED;
119+
}
120+
else if ( "false".equals( lazySelection ) ) {
121+
return FetchTiming.IMMEDIATE;
122+
}
123+
124+
throw new MappingException(
125+
String.format(
126+
"Unexpected lazy selection [%s] on '%s'",
127+
lazySelection,
128+
getName()
129+
),
130+
origin()
131+
);
132+
}
133+
134+
@Override
135+
public FetchStyle getFetchStyle() {
136+
// todo : handle batch fetches?
137+
138+
if ( getFetchSelectionString() == null ) {
139+
if ( getOuterJoinSelectionString() == null ) {
140+
return FetchStyle.SELECT;
141+
}
142+
else {
143+
if ( "auto".equals( getOuterJoinSelectionString() ) ) {
144+
return bindingContext().getMappingDefaults().areAssociationsLazy()
145+
? FetchStyle.SELECT
146+
: FetchStyle.JOIN;
147+
}
148+
else {
149+
return "true".equals( getOuterJoinSelectionString() ) ? FetchStyle.JOIN : FetchStyle.SELECT;
150+
}
151+
}
152+
}
153+
else {
154+
return "join".equals( getFetchSelectionString() ) ? FetchStyle.JOIN : FetchStyle.SELECT;
155+
}
156+
}
157+
158+
@Override
159+
// TODO: change to return the default name for a single column
160+
public List<Binder.DefaultNamingStrategy> getDefaultNamingStrategies(final String entityName, final String tableName, final AttributeBinding referencedAttributeBinding) {
161+
if ( CompositeAttributeBinding.class.isInstance( referencedAttributeBinding ) ) {
162+
CompositeAttributeBinding compositeAttributeBinding = CompositeAttributeBinding.class.cast(
163+
referencedAttributeBinding
164+
);
165+
List<Binder.DefaultNamingStrategy> result = new ArrayList<Binder.DefaultNamingStrategy>();
166+
for ( final AttributeBinding attributeBinding : compositeAttributeBinding.attributeBindings() ) {
167+
result.addAll( getDefaultNamingStrategies( entityName, tableName, attributeBinding ) );
168+
}
169+
return result;
170+
}
171+
else {
172+
List<Binder.DefaultNamingStrategy> result = new ArrayList<Binder.DefaultNamingStrategy>( 1 );
173+
result.add(
174+
new Binder.DefaultNamingStrategy() {
175+
@Override
176+
public String defaultName() {
177+
return bindingContext().getNamingStrategy().propertyToColumnName( getName() );
178+
}
179+
}
180+
);
181+
return result;
182+
}
183+
184+
}
185+
186+
@Override
187+
public JoinColumnResolutionDelegate getForeignKeyTargetColumnResolutionDelegate() {
188+
return propertyRef == null
189+
? null
190+
: new JoinColumnResolutionDelegateImpl();
191+
}
192+
193+
public class JoinColumnResolutionDelegateImpl implements JoinColumnResolutionDelegate {
194+
@Override
195+
public String getReferencedAttributeName() {
196+
return propertyRef;
197+
}
198+
199+
@Override
200+
public List<Value> getJoinColumns(JoinColumnResolutionContext context) {
201+
return context.resolveRelationalValuesForAttribute( propertyRef );
202+
}
203+
}
204+
205+
}

0 commit comments

Comments
 (0)