METAGEN-94 Initializing members of mapped superclasses lazily in order to correctly take access type declared by subtypes into account
This commit is contained in:
parent
b61dc5cc98
commit
399bc3542f
|
@ -39,7 +39,6 @@ import javax.lang.model.util.ElementFilter;
|
|||
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.annotation.AnnotationEmbeddable;
|
||||
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
|
||||
import org.hibernate.jpamodelgen.model.MetaEntity;
|
||||
import org.hibernate.jpamodelgen.util.Constants;
|
||||
|
@ -243,14 +242,15 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
continue;
|
||||
}
|
||||
|
||||
boolean requiresLazyMemberInitialization = false;
|
||||
AnnotationMetaEntity metaEntity;
|
||||
if ( TypeUtils.containsAnnotation( element, Constants.EMBEDDABLE ) ) {
|
||||
metaEntity = new AnnotationEmbeddable( (TypeElement) element, context );
|
||||
}
|
||||
else {
|
||||
metaEntity = new AnnotationMetaEntity( (TypeElement) element, context );
|
||||
if ( TypeUtils.containsAnnotation( element, Constants.EMBEDDABLE ) ||
|
||||
TypeUtils.containsAnnotation( element, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
requiresLazyMemberInitialization = true;
|
||||
}
|
||||
|
||||
metaEntity = new AnnotationMetaEntity( (TypeElement) element, context, requiresLazyMemberInitialization );
|
||||
|
||||
if ( alreadyExistingMetaEntity != null ) {
|
||||
metaEntity.mergeInMembers( alreadyExistingMetaEntity.getMembers() );
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
|
||||
* by the @authors tag. See the copyright.txt in the distribution for a
|
||||
* full listing of individual contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.hibernate.jpamodelgen.annotation;
|
||||
|
||||
import java.util.List;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.Context;
|
||||
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
||||
|
||||
/**
|
||||
* @author Max Andersen
|
||||
* @author Hardy Ferentschik
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class AnnotationEmbeddable extends AnnotationMetaEntity {
|
||||
|
||||
// Embeddables needs to be lazily initialized since the access type be determined by the class which is embedding
|
||||
// the entity. This might not be known until annotations are processed.
|
||||
// Also note, that if two different classes with different access types embed this entity the access type of the
|
||||
// embeddable will be the one of the last embedding entity processed. The result is not determined (that's ok
|
||||
// according to the spec)
|
||||
private boolean initialized;
|
||||
|
||||
public AnnotationEmbeddable(TypeElement element, Context context) {
|
||||
super( element, context, true );
|
||||
}
|
||||
|
||||
public List<MetaAttribute> getMembers() {
|
||||
if ( !initialized ) {
|
||||
getContext().logMessage( Diagnostic.Kind.OTHER, "Entity " + getQualifiedName() + " was lazily initialised." );
|
||||
init();
|
||||
initialized = true;
|
||||
}
|
||||
return super.getMembers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "AnnotationEmbeddable" );
|
||||
sb.append( "{element=" ).append( getElement() );
|
||||
sb.append( ", members=" );
|
||||
if ( initialized ) {
|
||||
sb.append( getMembers() );
|
||||
}
|
||||
else {
|
||||
sb.append( "[un-initalized]" );
|
||||
}
|
||||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import javax.lang.model.element.Modifier;
|
|||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.Context;
|
||||
import org.hibernate.jpamodelgen.ImportContextImpl;
|
||||
|
@ -38,7 +39,7 @@ import org.hibernate.jpamodelgen.util.Constants;
|
|||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* Class used to collect meta information about an annotated entity.
|
||||
* Class used to collect meta information about an annotated type (entity, embeddable or mapped superclass).
|
||||
*
|
||||
* @author Max Andersen
|
||||
* @author Hardy Ferentschik
|
||||
|
@ -49,15 +50,24 @@ public class AnnotationMetaEntity implements MetaEntity {
|
|||
private final ImportContext importContext;
|
||||
private final TypeElement element;
|
||||
private final Map<String, MetaAttribute> members;
|
||||
private Context context;
|
||||
private final Context context;
|
||||
|
||||
private AccessTypeInformation entityAccessTypeInfo;
|
||||
|
||||
public AnnotationMetaEntity(TypeElement element, Context context) {
|
||||
this( element, context, false );
|
||||
}
|
||||
/**
|
||||
* Whether the members of this type have already been initialized or not.
|
||||
* <p>
|
||||
* Embeddables and mapped super-classes need to be lazily initialized since the access type may be determined by
|
||||
* the class which is embedding or sub-classing the entity or super-class. This might not be known until
|
||||
* annotations are processed.
|
||||
* <p>
|
||||
* Also note, that if two different classes with different access types embed this entity or extend this mapped
|
||||
* super-class, the access type of the embeddable/super-class will be the one of the last embedding/sub-classing
|
||||
* entity processed. The result is not determined (that's ok according to the spec).
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
protected AnnotationMetaEntity(TypeElement element, Context context, boolean lazilyInitialised) {
|
||||
public AnnotationMetaEntity(TypeElement element, Context context, boolean lazilyInitialised) {
|
||||
this.element = element;
|
||||
this.context = context;
|
||||
this.members = new HashMap<String, MetaAttribute>();
|
||||
|
@ -89,6 +99,10 @@ public class AnnotationMetaEntity implements MetaEntity {
|
|||
}
|
||||
|
||||
public List<MetaAttribute> getMembers() {
|
||||
if ( !initialized ) {
|
||||
init();
|
||||
}
|
||||
|
||||
return new ArrayList<MetaAttribute>( members.values() );
|
||||
}
|
||||
|
||||
|
@ -134,6 +148,8 @@ public class AnnotationMetaEntity implements MetaEntity {
|
|||
}
|
||||
|
||||
protected final void init() {
|
||||
getContext().logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
||||
|
||||
TypeUtils.determineAccessTypeForHierarchy( element, context );
|
||||
entityAccessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
||||
|
||||
|
@ -142,6 +158,8 @@ public class AnnotationMetaEntity implements MetaEntity {
|
|||
|
||||
List<? extends Element> methodsOfClass = ElementFilter.methodsIn( element.getEnclosedElements() );
|
||||
addPersistentMembers( methodsOfClass, AccessType.PROPERTY );
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) {
|
||||
|
|
|
@ -268,7 +268,7 @@ public class JpaDescriptorParser {
|
|||
continue;
|
||||
}
|
||||
|
||||
XmlMetaEntity metaEntity = new XmlMetaEmbeddable( embeddable, pkg, getXmlMappedType( fqcn ), context );
|
||||
XmlMetaEntity metaEntity = new XmlMetaEntity( embeddable, pkg, getXmlMappedType( fqcn ), context );
|
||||
if ( context.containsMetaEmbeddable( fqcn ) ) {
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.WARNING,
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
|
||||
* by the @authors tag. See the copyright.txt in the distribution for a
|
||||
* full listing of individual contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.hibernate.jpamodelgen.xml;
|
||||
|
||||
import java.util.List;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.Context;
|
||||
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
||||
import org.hibernate.jpamodelgen.xml.jaxb.Embeddable;
|
||||
|
||||
/**
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class XmlMetaEmbeddable extends XmlMetaEntity {
|
||||
// Embeddables needs to be lazily initialized since the access type be determined by the class which is embedding
|
||||
// the entity. This might not be known until annotations are processed.
|
||||
// Also note, that if two different classes with different access types embed this entity the access type of the
|
||||
// embeddable will be the one of the last embedding entity processed. The result is not determined (that's ok
|
||||
// according to the spec)
|
||||
private boolean initialized;
|
||||
|
||||
public XmlMetaEmbeddable(Embeddable embeddable, String packageName, TypeElement element, Context context) {
|
||||
super( embeddable, packageName, element, context );
|
||||
}
|
||||
|
||||
public List<MetaAttribute> getMembers() {
|
||||
if ( !initialized ) {
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Entity " + getQualifiedName() + " was lazily initialised." );
|
||||
init();
|
||||
initialized = true;
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "XmlMetaEmbeddable" );
|
||||
sb.append( "{accessTypeInfo=" ).append( accessTypeInfo );
|
||||
sb.append( ", clazzName='" ).append( clazzName ).append( '\'' );
|
||||
sb.append( ", members=" );
|
||||
if ( initialized ) {
|
||||
sb.append( members );
|
||||
}
|
||||
else {
|
||||
sb.append( "[un-initalized]" );
|
||||
}
|
||||
sb.append( ", isMetaComplete=" ).append( isMetaComplete );
|
||||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -55,6 +55,8 @@ import org.hibernate.jpamodelgen.xml.jaxb.OneToMany;
|
|||
import org.hibernate.jpamodelgen.xml.jaxb.OneToOne;
|
||||
|
||||
/**
|
||||
* Collects XML-based meta information about an annotated type (entity, embeddable or mapped superclass).
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class XmlMetaEntity implements MetaEntity {
|
||||
|
@ -68,20 +70,33 @@ public class XmlMetaEntity implements MetaEntity {
|
|||
COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" );
|
||||
}
|
||||
|
||||
protected final String clazzName;
|
||||
protected final String packageName;
|
||||
protected final String defaultPackageName;
|
||||
protected final ImportContext importContext;
|
||||
protected final List<MetaAttribute> members = new ArrayList<MetaAttribute>();
|
||||
protected final TypeElement element;
|
||||
protected final Context context;
|
||||
protected final boolean isMetaComplete;
|
||||
private final String clazzName;
|
||||
private final String packageName;
|
||||
private final String defaultPackageName;
|
||||
private final ImportContext importContext;
|
||||
private final List<MetaAttribute> members = new ArrayList<MetaAttribute>();
|
||||
private final TypeElement element;
|
||||
private final Context context;
|
||||
private final boolean isMetaComplete;
|
||||
|
||||
private Attributes attributes;
|
||||
private EmbeddableAttributes embeddableAttributes;
|
||||
protected AccessTypeInformation accessTypeInfo;
|
||||
private AccessTypeInformation accessTypeInfo;
|
||||
|
||||
public XmlMetaEntity(Entity ormEntity, String defaultPackageName, TypeElement element, Context context) {
|
||||
/**
|
||||
* Whether the members of this type have already been initialized or not.
|
||||
* <p>
|
||||
* Embeddables and mapped super-classes need to be lazily initialized since the access type may be determined by
|
||||
* the class which is embedding or sub-classing the entity or super-class. This might not be known until
|
||||
* annotations are processed.
|
||||
* <p>
|
||||
* Also note, that if two different classes with different access types embed this entity or extend this mapped
|
||||
* super-class, the access type of the embeddable/super-class will be the one of the last embedding/sub-classing
|
||||
* entity processed. The result is not determined (that's ok according to the spec).
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
XmlMetaEntity(Entity ormEntity, String defaultPackageName, TypeElement element, Context context) {
|
||||
this( ormEntity.getClazz(), defaultPackageName, element, context, ormEntity.isMetadataComplete() );
|
||||
this.attributes = ormEntity.getAttributes();
|
||||
this.embeddableAttributes = null;
|
||||
|
@ -89,7 +104,7 @@ public class XmlMetaEntity implements MetaEntity {
|
|||
init();
|
||||
}
|
||||
|
||||
protected XmlMetaEntity(MappedSuperclass mappedSuperclass, String defaultPackageName, TypeElement element, Context context) {
|
||||
XmlMetaEntity(MappedSuperclass mappedSuperclass, String defaultPackageName, TypeElement element, Context context) {
|
||||
this(
|
||||
mappedSuperclass.getClazz(),
|
||||
defaultPackageName,
|
||||
|
@ -99,11 +114,9 @@ public class XmlMetaEntity implements MetaEntity {
|
|||
);
|
||||
this.attributes = mappedSuperclass.getAttributes();
|
||||
this.embeddableAttributes = null;
|
||||
// entities can be directly initialised
|
||||
init();
|
||||
}
|
||||
|
||||
protected XmlMetaEntity(Embeddable embeddable, String defaultPackageName, TypeElement element, Context context) {
|
||||
XmlMetaEntity(Embeddable embeddable, String defaultPackageName, TypeElement element, Context context) {
|
||||
this( embeddable.getClazz(), defaultPackageName, element, context, embeddable.isMetadataComplete() );
|
||||
this.attributes = null;
|
||||
this.embeddableAttributes = embeddable.getAttributes();
|
||||
|
@ -127,7 +140,9 @@ public class XmlMetaEntity implements MetaEntity {
|
|||
this.isMetaComplete = initIsMetaComplete( metaComplete );
|
||||
}
|
||||
|
||||
protected final void init() {
|
||||
private final void init() {
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
||||
|
||||
this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
||||
if ( attributes != null ) {
|
||||
parseAttributes( attributes );
|
||||
|
@ -135,6 +150,8 @@ public class XmlMetaEntity implements MetaEntity {
|
|||
else {
|
||||
parseEmbeddableAttributes( embeddableAttributes );
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public String getSimpleName() {
|
||||
|
@ -150,6 +167,10 @@ public class XmlMetaEntity implements MetaEntity {
|
|||
}
|
||||
|
||||
public List<MetaAttribute> getMembers() {
|
||||
if ( !initialized ) {
|
||||
init();
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue