/**
* inSecondPass can only be used to apply right away the second pass of a composite-element
* Because it's a value type, there is no bidirectional association, hence second pass
* ordering does not matter
*/
Component comp = createComponent( propertyHolder, inferredData, isComponentEmbedded, isIdentifierMapper, mappings );
String subpath = BinderHelper.getPath( propertyHolder, inferredData );
LOG.tracev( "Binding component with path: {0}", subpath );
PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder(
comp,
subpath,
inferredData,
propertyHolder,
mappings
);
// propertyHolder here is the owner of the component property. Tell it we are about to start the component...
propertyHolder.startingProperty( inferredData.getProperty() );
final XClass xClassProcessed = inferredData.getPropertyClass();
List<PropertyData> classElements = new ArrayList<PropertyData>();
XClass returnedClassOrElement = inferredData.getClassOrElement();
List<PropertyData> baseClassElements = null;
Map<String, PropertyData> orderedBaseClassElements = new HashMap<String, PropertyData>();
XClass baseReturnedClassOrElement;
if ( baseInferredData != null ) {
baseClassElements = new ArrayList<PropertyData>();
baseReturnedClassOrElement = baseInferredData.getClassOrElement();
bindTypeDefs( baseReturnedClassOrElement, mappings );
PropertyContainer propContainer = new PropertyContainer( baseReturnedClassOrElement, xClassProcessed );
addElementsOfClass( baseClassElements, propertyAccessor, propContainer, mappings );
for ( PropertyData element : baseClassElements ) {
orderedBaseClassElements.put( element.getPropertyName(), element );
}
}
//embeddable elements can have type defs
bindTypeDefs( returnedClassOrElement, mappings );
PropertyContainer propContainer = new PropertyContainer( returnedClassOrElement, xClassProcessed );
addElementsOfClass( classElements, propertyAccessor, propContainer, mappings );
//add elements of the embeddable superclass
XClass superClass = xClassProcessed.getSuperclass();
while ( superClass != null && superClass.isAnnotationPresent( MappedSuperclass.class ) ) {
//FIXME: proper support of typevariables incl var resolved at upper levels
propContainer = new PropertyContainer( superClass, xClassProcessed );
addElementsOfClass( classElements, propertyAccessor, propContainer, mappings );
superClass = superClass.getSuperclass();
}
if ( baseClassElements != null ) {
//useful to avoid breaking pre JPA 2 mappings
if ( !hasAnnotationsOnIdClass( xClassProcessed ) ) {
for ( int i = 0; i < classElements.size(); i++ ) {
final PropertyData idClassPropertyData = classElements.get( i );
final PropertyData entityPropertyData = orderedBaseClassElements.get( idClassPropertyData.getPropertyName() );
if ( propertyHolder.isInIdClass() ) {
if ( entityPropertyData == null ) {
throw new AnnotationException(
"Property of @IdClass not found in entity "
+ baseInferredData.getPropertyClass().getName() + ": "
+ idClassPropertyData.getPropertyName()
);
}
final boolean hasXToOneAnnotation = entityPropertyData.getProperty()
.isAnnotationPresent( ManyToOne.class )
|| entityPropertyData.getProperty().isAnnotationPresent( OneToOne.class );
final boolean isOfDifferentType = !entityPropertyData.getClassOrElement()
.equals( idClassPropertyData.getClassOrElement() );
if ( hasXToOneAnnotation && isOfDifferentType ) {
//don't replace here as we need to use the actual original return type
//the annotation overriding will be dealt with by a mechanism similar to @MapsId
}
else {
classElements.set( i, entityPropertyData ); //this works since they are in the same order
}
}
else {
classElements.set( i, entityPropertyData ); //this works since they are in the same order
}
}
}
}
for ( PropertyData propertyAnnotatedElement : classElements ) {
processElementAnnotations(
subHolder, isNullable ?
Nullability.NO_CONSTRAINT :
Nullability.FORCED_NOT_NULL,
propertyAnnotatedElement,
new HashMap<String, IdGenerator>(), entityBinder, isIdentifierMapper, isComponentEmbedded,
inSecondPass, mappings, inheritanceStatePerClass
);
XProperty property = propertyAnnotatedElement.getProperty();
if ( property.isAnnotationPresent( GeneratedValue.class ) &&
property.isAnnotationPresent( Id.class ) ) {
//clone classGenerator and override with local values
Map<String, IdGenerator> localGenerators = new HashMap<String, IdGenerator>();
localGenerators.putAll( buildLocalGenerators( property, mappings ) );
GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class );
String generatorType = generatedValue != null ? generatorType(
generatedValue.strategy(), mappings
) : "assigned";
String generator = generatedValue != null ? generatedValue.generator() : BinderHelper.ANNOTATION_STRING_DEFAULT;
BinderHelper.makeIdGenerator(
( SimpleValue ) comp.getProperty( property.getName() ).getValue(),
generatorType,
generator,
mappings,
localGenerators
);