[hibernate-commits] Hibernate SVN: r18773 - in jpamodelgen/trunk/src: main/java/org/hibernate/jpamodelgen/annotation and 5 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Feb 10 21:43:52 EST 2010


Author: hardy.ferentschik
Date: 2010-02-10 21:43:51 -0500 (Wed, 10 Feb 2010)
New Revision: 18773

Added:
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/Constants.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java
   jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java
   jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java
   jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java
   jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml
Modified:
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java
   jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java
   jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java
   jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java
Log:
METAGEN-9 Added support for Embeddable

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -26,6 +26,7 @@
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
 import javax.persistence.AccessType;
 import javax.tools.Diagnostic;
 
@@ -87,6 +88,14 @@
 		return pe;
 	}
 
+	public Elements getElementUtils() {
+		return pe.getElementUtils();
+	}
+
+	public Types getTypeUtils() {
+		return pe.getTypeUtils();
+	}
+
 	public String getPersistenceXmlLocation() {
 		return persistenceXmlLocation;
 	}

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -18,6 +18,7 @@
 package org.hibernate.jpamodelgen;
 
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import javax.annotation.processing.AbstractProcessor;
@@ -30,13 +31,22 @@
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.SimpleTypeVisitor6;
 import javax.persistence.Embeddable;
 import javax.persistence.Entity;
 import javax.persistence.MappedSuperclass;
 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;
+import org.hibernate.jpamodelgen.util.StringUtil;
 import org.hibernate.jpamodelgen.util.TypeUtils;
 import org.hibernate.jpamodelgen.xml.XmlParser;
 
@@ -86,15 +96,10 @@
 
 		if ( !xmlProcessed ) {
 			XmlParser parser = new XmlParser( context );
-			parser.parsePersistenceXml();
+			parser.parseXml();
 			xmlProcessed = true;
 		}
 
-		if ( !hostJPAAnnotations( annotations ) ) {
-			context.logMessage( Diagnostic.Kind.OTHER, "Current processing round does not contain entities" );
-			return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
-		}
-
 		if ( context.isPersistenceUnitCompletelyXmlConfigured() ) {
 			context.logMessage(
 					Diagnostic.Kind.OTHER,
@@ -105,8 +110,8 @@
 
 		Set<? extends Element> elements = roundEnvironment.getRootElements();
 		for ( Element element : elements ) {
-			if ( TypeUtils.containsAnnotation( element, Entity.class, MappedSuperclass.class, Embeddable.class ) ) {
-				context.logMessage( Diagnostic.Kind.OTHER, "Processing " + element.toString() );
+			if ( isJPAEntity( element ) ) {
+				context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element.toString() );
 				handleRootElementAnnotationMirrors( element );
 			}
 		}
@@ -116,59 +121,162 @@
 
 	private void createMetaModelClasses() {
 		for ( MetaEntity entity : context.getMetaEntities() ) {
-			context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for " + entity );
+			context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for entity " + entity );
 			ClassWriter.writeFile( entity, context );
 		}
 
-		for ( MetaEntity entity : context.getMetaSuperclassOrEmbeddable() ) {
-			context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for " + entity );
-			ClassWriter.writeFile( entity, context );
+		Collection<MetaEntity> toProcessEntities = context.getMetaSuperclassOrEmbeddable();
+		while ( !toProcessEntities.isEmpty() ) {
+			Set<MetaEntity> processedEntities = new HashSet<MetaEntity>();
+			for ( MetaEntity entity : toProcessEntities ) {
+				if ( containedInEntity( toProcessEntities, entity ) ) {
+					continue;
+				}
+				context.logMessage(
+						Diagnostic.Kind.OTHER, "Writing meta model for embeddable/mapped superclass" + entity
+				);
+				ClassWriter.writeFile( entity, context );
+				processedEntities.add( entity );
+			}
+			toProcessEntities.removeAll( processedEntities );
 		}
 	}
 
-	private boolean hostJPAAnnotations(Collection<? extends TypeElement> annotations) {
-		for ( TypeElement type : annotations ) {
-			if ( TypeUtils.isTypeElementOfType( type, Entity.class ) ) {
-				return true;
+	private boolean containedInEntity(Collection<MetaEntity> entities, MetaEntity containedEntity) {
+		ContainsAttributeTypeVisitor visitor = new ContainsAttributeTypeVisitor(
+				containedEntity.getTypeElement(), context
+		);
+		for ( MetaEntity entity : entities ) {
+			if ( entity.equals( containedEntity ) ) {
+				continue;
 			}
-			else if ( TypeUtils.isTypeElementOfType( type, Embeddable.class ) ) {
-				return true;
+			for ( Element subElement : ElementFilter.fieldsIn( entity.getTypeElement().getEnclosedElements() ) ) {
+				TypeMirror mirror = subElement.asType();
+				if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) {
+					 continue;
+				}
+				boolean contains = mirror.accept( visitor, subElement );
+				if ( contains ) {
+					return true;
+				}
 			}
-			else if ( TypeUtils.isTypeElementOfType( type, MappedSuperclass.class ) ) {
-				return true;
+			for ( Element subElement : ElementFilter.methodsIn( entity.getTypeElement().getEnclosedElements() ) ) {
+				TypeMirror mirror = subElement.asType();
+				if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) {
+					continue;
+				}
+				boolean contains = mirror.accept( visitor, subElement );
+				if ( contains ) {
+					return true;
+				}
 			}
 		}
 		return false;
 	}
 
+	private boolean isJPAEntity(Element element) {
+		return TypeUtils.containsAnnotation( element, Entity.class, MappedSuperclass.class, Embeddable.class );
+	}
+
 	private void handleRootElementAnnotationMirrors(final Element element) {
 		List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
 		for ( AnnotationMirror mirror : annotationMirrors ) {
-			if ( element.getKind() == ElementKind.CLASS ) {
-				String fqn = ( ( TypeElement ) element ).getQualifiedName().toString();
-				MetaEntity alreadyExistingMetaEntity = context.getMetaEntity( fqn );
-				if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) {
-					String msg = "Skipping processing of annotations for " + fqn + " since xml configuration is metadata complete.";
-					context.logMessage( Diagnostic.Kind.OTHER, msg );
-					continue;
-				}
+			if ( !ElementKind.CLASS.equals( element.getKind() ) ) {
+				continue;
+			}
 
-				AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
-				if ( alreadyExistingMetaEntity != null ) {
-					metaEntity.mergeInMembers( alreadyExistingMetaEntity.getMembers() );
-				}
-				addMetaEntityToContext( mirror, metaEntity );
+			String fqn = ( ( TypeElement ) element ).getQualifiedName().toString();
+			MetaEntity alreadyExistingMetaEntity = tryGettingExistingEntityFromContext( mirror, fqn );
+			if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) {
+				String msg = "Skipping processing of annotations for " + fqn + " since xml configuration is metadata complete.";
+				context.logMessage( Diagnostic.Kind.OTHER, msg );
+				continue;
 			}
+
+			AnnotationMetaEntity metaEntity;
+			if ( TypeUtils.containsAnnotation( element, Embeddable.class ) ) {
+				metaEntity = new AnnotationEmbeddable( ( TypeElement ) element, context );
+			}
+			else {
+				metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
+			}
+
+			if ( alreadyExistingMetaEntity != null ) {
+				metaEntity.mergeInMembers( alreadyExistingMetaEntity.getMembers() );
+			}
+			addMetaEntityToContext( mirror, metaEntity );
 		}
 	}
 
+	private MetaEntity tryGettingExistingEntityFromContext(AnnotationMirror mirror, String fqn) {
+		MetaEntity alreadyExistingMetaEntity = null;
+		if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) {
+			alreadyExistingMetaEntity = context.getMetaEntity( fqn );
+		}
+		else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class )
+				|| TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) {
+			alreadyExistingMetaEntity = context.getMetaSuperclassOrEmbeddable( fqn );
+		}
+		return alreadyExistingMetaEntity;
+	}
+
 	private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) {
 		if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) {
 			context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity );
 		}
-		else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class )
-				|| TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) {
+		else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class ) ) {
 			context.addMetaSuperclassOrEmbeddable( metaEntity.getQualifiedName(), metaEntity );
 		}
+		else if ( TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) {
+			context.addMetaSuperclassOrEmbeddable( metaEntity.getQualifiedName(), metaEntity );
+		}
 	}
+
+
+	class ContainsAttributeTypeVisitor extends SimpleTypeVisitor6<Boolean, Element> {
+
+		private Context context;
+		private TypeElement type;
+
+		ContainsAttributeTypeVisitor(TypeElement elem, Context context) {
+			this.context = context;
+			this.type = elem;
+		}
+
+		@Override
+		public Boolean visitDeclared(DeclaredType declaredType, Element element) {
+			TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType );
+
+			String fqNameOfReturnType = returnedElement.getQualifiedName().toString();
+			String collection = Constants.COLLECTIONS.get( fqNameOfReturnType );
+			if ( collection != null ) {
+				TypeMirror collectionElementType = TypeUtils.getCollectionElementType(
+						declaredType, fqNameOfReturnType, null, context
+				);
+				returnedElement = ( TypeElement ) context.getTypeUtils().asElement( collectionElementType );
+			}
+
+			if ( type.getQualifiedName().toString().equals( returnedElement.getQualifiedName().toString() ) ) {
+				return Boolean.TRUE;
+			}
+			else {
+				return Boolean.FALSE;
+			}
+		}
+
+		@Override
+		public Boolean visitExecutable(ExecutableType t, Element element) {
+			if ( !element.getKind().equals( ElementKind.METHOD ) ) {
+				return Boolean.FALSE;
+			}
+
+			String string = element.getSimpleName().toString();
+			if ( !StringUtil.isPropertyName( string ) ) {
+				return Boolean.FALSE;
+			}
+
+			TypeMirror returnType = t.getReturnType();
+			return returnType.accept( this, element );
+		}
+	}
 }

Copied: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java (from rev 18756, jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java)
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java	                        (rev 0)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,69 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, 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 ) {
+			context.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( element );
+		sb.append( ", members=" );
+		if ( initialized ) {
+			sb.append( members );
+		}
+		else {
+			sb.append( "[un-initalized]" );
+		}
+		sb.append( '}' );
+		return sb.toString();
+	}
+}
\ No newline at end of file

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -47,7 +47,7 @@
 	}
 
 	public String getPropertyName() {
-		Elements elementsUtil = parent.getContext().getProcessingEnvironment().getElementUtils();
+		Elements elementsUtil = parent.getContext().getElementUtils();
 		if ( element.getKind() == ElementKind.FIELD ) {
 			return element.getSimpleName().toString();
 		}

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -36,7 +36,6 @@
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
 import javax.lang.model.util.SimpleTypeVisitor6;
 import javax.persistence.AccessType;
 import javax.persistence.Basic;
@@ -53,10 +52,10 @@
 import org.hibernate.jpamodelgen.AccessTypeInformation;
 import org.hibernate.jpamodelgen.Context;
 import org.hibernate.jpamodelgen.ImportContextImpl;
-import org.hibernate.jpamodelgen.MetaModelGenerationException;
 import org.hibernate.jpamodelgen.model.ImportContext;
 import org.hibernate.jpamodelgen.model.MetaAttribute;
 import org.hibernate.jpamodelgen.model.MetaEntity;
+import org.hibernate.jpamodelgen.util.Constants;
 import org.hibernate.jpamodelgen.util.StringUtil;
 import org.hibernate.jpamodelgen.util.TypeUtils;
 
@@ -67,54 +66,25 @@
  */
 public class AnnotationMetaEntity implements MetaEntity {
 
-	static Map<String, String> COLLECTIONS = new HashMap<String, String>();
+	protected final ImportContext importContext;
+	protected final TypeElement element;
+	protected final Map<String, MetaAttribute> members;
+	protected Context context;
 
-	static {
-		COLLECTIONS.put( "java.util.Collection", "javax.persistence.metamodel.CollectionAttribute" );
-		COLLECTIONS.put( "java.util.Set", "javax.persistence.metamodel.SetAttribute" );
-		COLLECTIONS.put( "java.util.List", "javax.persistence.metamodel.ListAttribute" );
-		COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" );
-	}
-
-	static List<String> BASIC_TYPES = new ArrayList<String>();
-
-	static {
-		BASIC_TYPES.add( "java.lang.String" );
-		BASIC_TYPES.add( "java.lang.Boolean" );
-		BASIC_TYPES.add( "java.lang.Byte" );
-		BASIC_TYPES.add( "java.lang.Character" );
-		BASIC_TYPES.add( "java.lang.Short" );
-		BASIC_TYPES.add( "java.lang.Integer" );
-		BASIC_TYPES.add( "java.lang.Long" );
-		BASIC_TYPES.add( "java.lang.Float" );
-		BASIC_TYPES.add( "java.lang.Double" );
-		BASIC_TYPES.add( "java.math.BigInteger" );
-		BASIC_TYPES.add( "java.math.BigDecimal" );
-		BASIC_TYPES.add( "java.util.Date" );
-		BASIC_TYPES.add( "java.util.Calendar" );
-		BASIC_TYPES.add( "java.sql.Date" );
-		BASIC_TYPES.add( "java.sql.Time" );
-		BASIC_TYPES.add( "java.sql.Timestamp" );
-	}
-
-	static List<String> BASIC_ARRAY_TYPES = new ArrayList<String>();
-
-	static {
-		BASIC_ARRAY_TYPES.add( "java.lang.Character" );
-		BASIC_ARRAY_TYPES.add( "java.lang.Byte" );
-	}
-
-	private final TypeElement element;
-	private final ImportContext importContext;
-	private Context context;
-	private Map<String, MetaAttribute> members;
 	private AccessTypeInformation entityAccessTypeInfo;
 
 	public AnnotationMetaEntity(TypeElement element, Context context) {
+		this( element, context, false );
+	}
+
+	protected AnnotationMetaEntity(TypeElement element, Context context, boolean lazilyInitialised) {
 		this.element = element;
 		this.context = context;
-		importContext = new ImportContextImpl( getPackageName() );
-		init();
+		this.members = new HashMap<String, MetaAttribute>();
+		this.importContext = new ImportContextImpl( getPackageName() );
+		if ( !lazilyInitialised ) {
+			init();
+		}
 	}
 
 	public Context getContext() {
@@ -130,8 +100,8 @@
 	}
 
 	public String getPackageName() {
-		PackageElement packageOf = context.getProcessingEnvironment().getElementUtils().getPackageOf( element );
-		return context.getProcessingEnvironment().getElementUtils().getName( packageOf.getQualifiedName() ).toString();
+		PackageElement packageOf = context.getElementUtils().getPackageOf( element );
+		return context.getElementUtils().getName( packageOf.getQualifiedName() ).toString();
 	}
 
 	public List<MetaAttribute> getMembers() {
@@ -149,6 +119,16 @@
 		}
 	}
 
+	@Override
+	public String toString() {
+		final StringBuilder sb = new StringBuilder();
+		sb.append( "AnnotationMetaEntity" );
+		sb.append( "{element=" ).append( element );
+		sb.append( ", members=" ).append( members );
+		sb.append( '}' );
+		return sb.toString();
+	}
+
 	private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) {
 		for ( Element memberOfClass : membersOfClass ) {
 			AccessType forcedAccessType = TypeUtils.determineAnnotationSpecifiedAccessType( memberOfClass );
@@ -170,18 +150,7 @@
 		}
 	}
 
-	@Override
-	public String toString() {
-		final StringBuilder sb = new StringBuilder();
-		sb.append( "AnnotationMetaEntity" );
-		sb.append( "{element=" ).append( element );
-		sb.append( ", members=" ).append( members );
-		sb.append( '}' );
-		return sb.toString();
-	}
-
-	private void init() {
-		members = new HashMap<String, MetaAttribute>();
+	protected void init() {
 		TypeUtils.determineAccessTypeForHierarchy( element, context );
 		entityAccessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
 
@@ -248,21 +217,18 @@
 
 		@Override
 		public AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) {
-			TypeElement returnedElement = ( TypeElement ) context.getProcessingEnvironment()
-					.getTypeUtils()
-					.asElement( declaredType );
+			TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType );
 			// WARNING: .toString() is necessary here since Name equals does not compare to String
 			String fqNameOfReturnType = returnedElement.getQualifiedName().toString();
-			String collection = COLLECTIONS.get( fqNameOfReturnType );
+			String collection = Constants.COLLECTIONS.get( fqNameOfReturnType );
 			String targetEntity = getTargetEntity( element.getAnnotationMirrors() );
 			if ( collection != null ) {
 				if ( TypeUtils.containsAnnotation( element, ElementCollection.class ) ) {
 					String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() );
-					TypeMirror collectionElementType = getCollectionElementType(
-							declaredType, fqNameOfReturnType, explicitTargetEntity
+					TypeMirror collectionElementType = TypeUtils.getCollectionElementType(
+							declaredType, fqNameOfReturnType, explicitTargetEntity, context
 					);
-					final TypeElement collectionElement = ( TypeElement ) context.getProcessingEnvironment()
-							.getTypeUtils()
+					final TypeElement collectionElement = ( TypeElement ) context.getTypeUtils()
 							.asElement( collectionElementType );
 					AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( collectionElement.getQualifiedName().toString() );
 					if ( accessTypeInfo == null ) {
@@ -281,8 +247,6 @@
 					else {
 						accessTypeInfo.setDefaultAccessType( entityAccessTypeInfo.getAccessType() );
 					}
-					AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( collectionElement, context );
-					context.addMetaSuperclassOrEmbeddable( metaEntity.getQualifiedName(), metaEntity );
 				}
 				if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
 					return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity );
@@ -353,28 +317,6 @@
 			);
 		}
 
-		private TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, String explicitTargetEntityName) {
-			TypeMirror collectionElementType;
-			if ( explicitTargetEntityName != null ) {
-				Elements elements = context.getProcessingEnvironment().getElementUtils();
-				TypeElement element = elements.getTypeElement( explicitTargetEntityName );
-				collectionElementType = element.asType();
-			}
-			else {
-				List<? extends TypeMirror> typeArguments = t.getTypeArguments();
-				if ( typeArguments.size() == 0 ) {
-					throw new MetaModelGenerationException( "Unable to determine collection type for property in " + getSimpleName() );
-				}
-				else if ( Map.class.getCanonicalName().equals( fqNameOfReturnedType ) ) {
-					collectionElementType = t.getTypeArguments().get( 1 );
-				}
-				else {
-					collectionElementType = t.getTypeArguments().get( 0 );
-				}
-			}
-			return collectionElementType;
-		}
-
 		private String getElementType(DeclaredType declaredType, String targetEntity) {
 			if ( targetEntity != null ) {
 				return targetEntity;
@@ -446,8 +388,8 @@
 	}
 
 	/**
-	 * Checks whether the visited type is a basic attibute according to the JPA 2 spec
-	 * ( secction 2.8 Mapping Defaults for Non-Relationship Fields or Properties)
+	 * Checks whether the visited type is a basic attribute according to the JPA 2 spec
+	 * ( section 2.8 Mapping Defaults for Non-Relationship Fields or Properties)
 	 */
 	class BasicAttributeVisitor extends SimpleTypeVisitor6<Boolean, Element> {
 		@Override
@@ -458,11 +400,9 @@
 		@Override
 		public Boolean visitArray(ArrayType t, Element element) {
 			TypeMirror componentMirror = t.getComponentType();
-			TypeElement componentElement = ( TypeElement ) context.getProcessingEnvironment()
-					.getTypeUtils()
-					.asElement( componentMirror );
+			TypeElement componentElement = ( TypeElement ) context.getTypeUtils().asElement( componentMirror );
 
-			return BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() );
+			return Constants.BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() );
 		}
 
 		@Override
@@ -474,16 +414,14 @@
 			if ( ElementKind.CLASS.equals( element.getKind() ) ) {
 				TypeElement typeElement = ( ( TypeElement ) element );
 				String typeName = typeElement.getQualifiedName().toString();
-				if ( BASIC_TYPES.contains( typeName ) ) {
+				if ( Constants.BASIC_TYPES.contains( typeName ) ) {
 					return Boolean.TRUE;
 				}
 				if ( TypeUtils.containsAnnotation( element, Embeddable.class ) ) {
 					return Boolean.TRUE;
 				}
 				for ( TypeMirror mirror : typeElement.getInterfaces() ) {
-					TypeElement interfaceElement = ( TypeElement ) context.getProcessingEnvironment()
-							.getTypeUtils()
-							.asElement( mirror );
+					TypeElement interfaceElement = ( TypeElement ) context.getTypeUtils().asElement( mirror );
 					if ( "java.io.Serializable".equals( interfaceElement.getQualifiedName().toString() ) ) {
 						return Boolean.TRUE;
 					}

Added: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/Constants.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/Constants.java	                        (rev 0)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/Constants.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,69 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class Constants {
+	public static Map<String, String> COLLECTIONS = new HashMap<String, String>();
+
+	static {
+		COLLECTIONS.put( "java.util.Collection", "javax.persistence.metamodel.CollectionAttribute" );
+		COLLECTIONS.put( "java.util.Set", "javax.persistence.metamodel.SetAttribute" );
+		COLLECTIONS.put( "java.util.List", "javax.persistence.metamodel.ListAttribute" );
+		COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" );
+	}
+
+	public static List<String> BASIC_TYPES = new ArrayList<String>();
+
+	static {
+		BASIC_TYPES.add( "java.lang.String" );
+		BASIC_TYPES.add( "java.lang.Boolean" );
+		BASIC_TYPES.add( "java.lang.Byte" );
+		BASIC_TYPES.add( "java.lang.Character" );
+		BASIC_TYPES.add( "java.lang.Short" );
+		BASIC_TYPES.add( "java.lang.Integer" );
+		BASIC_TYPES.add( "java.lang.Long" );
+		BASIC_TYPES.add( "java.lang.Float" );
+		BASIC_TYPES.add( "java.lang.Double" );
+		BASIC_TYPES.add( "java.math.BigInteger" );
+		BASIC_TYPES.add( "java.math.BigDecimal" );
+		BASIC_TYPES.add( "java.util.Date" );
+		BASIC_TYPES.add( "java.util.Calendar" );
+		BASIC_TYPES.add( "java.sql.Date" );
+		BASIC_TYPES.add( "java.sql.Time" );
+		BASIC_TYPES.add( "java.sql.Timestamp" );
+	}
+
+	public static List<String> BASIC_ARRAY_TYPES = new ArrayList<String>();
+
+	static {
+		BASIC_ARRAY_TYPES.add( "java.lang.Character" );
+		BASIC_ARRAY_TYPES.add( "java.lang.Byte" );
+	}
+
+	private Constants(){}
+}
+
+

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -29,12 +29,17 @@
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.type.TypeVariable;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
 import javax.lang.model.util.Types;
 import javax.persistence.Access;
 import javax.persistence.AccessType;
+import javax.persistence.Embeddable;
 import javax.persistence.EmbeddedId;
 import javax.persistence.Entity;
 import javax.persistence.Id;
@@ -43,6 +48,7 @@
 
 import org.hibernate.jpamodelgen.AccessTypeInformation;
 import org.hibernate.jpamodelgen.Context;
+import org.hibernate.jpamodelgen.MetaModelGenerationException;
 
 /**
  * Utility class.
@@ -94,7 +100,7 @@
 	public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
 		if ( type instanceof TypeVariable ) {
 			final TypeMirror compositeUpperBound = ( ( TypeVariable ) type ).getUpperBound();
-			final Types types = context.getProcessingEnvironment().getTypeUtils();
+			final Types types = context.getTypeUtils();
 			final List<? extends TypeMirror> upperBounds = types.directSupertypes( compositeUpperBound );
 			if ( upperBounds.size() == 0 ) {
 				return compositeUpperBound.toString();
@@ -194,7 +200,7 @@
 
 	public static void determineAccessTypeForHierarchy(TypeElement searchedElement, Context context) {
 		String fqcn = searchedElement.getQualifiedName().toString();
-		context.logMessage( Diagnostic.Kind.OTHER, "check class " + fqcn );
+		context.logMessage( Diagnostic.Kind.OTHER, "Determining access type for " + fqcn );
 		AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn );
 
 		if ( accessTypeInfo != null && accessTypeInfo.isAccessTypeResolved() ) {
@@ -213,6 +219,7 @@
 			);
 			accessTypeInfo = new AccessTypeInformation( fqcn, forcedAccessType, null );
 			context.addAccessTypeInformation( fqcn, accessTypeInfo );
+			updateEmbeddableAccessType( searchedElement, context, forcedAccessType );
 			return;
 		}
 
@@ -223,6 +230,7 @@
 		if ( defaultAccessType != null ) {
 			accessTypeInfo = new AccessTypeInformation( fqcn, null, defaultAccessType );
 			context.addAccessTypeInformation( fqcn, accessTypeInfo );
+			updateEmbeddableAccessType( searchedElement, context, defaultAccessType );
 			return;
 		}
 
@@ -235,6 +243,55 @@
 		context.addAccessTypeInformation( fqcn, accessTypeInfo );
 	}
 
+	public static TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, String explicitTargetEntityName, Context context) {
+		TypeMirror collectionElementType;
+		if ( explicitTargetEntityName != null ) {
+			Elements elements = context.getElementUtils();
+			TypeElement element = elements.getTypeElement( explicitTargetEntityName );
+			collectionElementType = element.asType();
+		}
+		else {
+			List<? extends TypeMirror> typeArguments = t.getTypeArguments();
+			if ( typeArguments.size() == 0 ) {
+				throw new MetaModelGenerationException( "Unable to determine collection type" );
+			}
+			else if ( Map.class.getCanonicalName().equals( fqNameOfReturnedType ) ) {
+				collectionElementType = t.getTypeArguments().get( 1 );
+			}
+			else {
+				collectionElementType = t.getTypeArguments().get( 0 );
+			}
+		}
+		return collectionElementType;
+	}
+
+	private static void updateEmbeddableAccessType(TypeElement element, Context context, AccessType defaultAccessType) {
+		List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() );
+		for ( Element field : fieldsOfClass ) {
+			updateEmbeddableAccessTypeForMember( context, defaultAccessType, field );
+		}
+
+		List<? extends Element> methodOfClass = ElementFilter.methodsIn( element.getEnclosedElements() );
+		for ( Element method : methodOfClass ) {
+			updateEmbeddableAccessTypeForMember( context, defaultAccessType, method );
+		}
+	}
+
+	private static void updateEmbeddableAccessTypeForMember(Context context, AccessType defaultAccessType, Element member) {
+		EmbeddedAttributeVisitor visitor = new EmbeddedAttributeVisitor( context );
+		String embeddedClassName = member.asType().accept( visitor, member );
+		if ( embeddedClassName != null ) {
+			AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( embeddedClassName );
+			if ( accessTypeInfo == null ) {
+				accessTypeInfo = new AccessTypeInformation( embeddedClassName, null, defaultAccessType );
+				context.addAccessTypeInformation( embeddedClassName, accessTypeInfo );
+			}
+			else {
+				accessTypeInfo.setDefaultAccessType( defaultAccessType );
+			}
+		}
+	}
+
 	private static AccessType getDefaultAccessForHierarchy(TypeElement element, Context context) {
 		AccessType defaultAccessType = null;
 		TypeElement superClass = element;
@@ -268,7 +325,7 @@
 		List<? extends Element> myMembers = searchedElement.getEnclosedElements();
 		for ( Element subElement : myMembers ) {
 			List<? extends AnnotationMirror> entityAnnotations =
-					context.getProcessingEnvironment().getElementUtils().getAllAnnotationMirrors( subElement );
+					context.getElementUtils().getAllAnnotationMirrors( subElement );
 			for ( Object entityAnnotation : entityAnnotations ) {
 				AnnotationMirror annotationMirror = ( AnnotationMirror ) entityAnnotation;
 				if ( isIdAnnotation( annotationMirror ) ) {
@@ -322,4 +379,38 @@
 			return ElementKind.METHOD;
 		}
 	}
+
+	static class EmbeddedAttributeVisitor extends SimpleTypeVisitor6<String, Element> {
+
+		private Context context;
+
+		EmbeddedAttributeVisitor(Context context) {
+			this.context = context;
+		}
+
+		@Override
+		public String visitDeclared(DeclaredType declaredType, Element element) {
+			TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType );
+			String fqNameOfReturnType = null;
+			if ( containsAnnotation( returnedElement, Embeddable.class ) ) {
+				fqNameOfReturnType = returnedElement.getQualifiedName().toString();
+			}
+			return fqNameOfReturnType;
+		}
+
+		@Override
+		public String visitExecutable(ExecutableType t, Element p) {
+			if ( !p.getKind().equals( ElementKind.METHOD ) ) {
+				return null;
+			}
+
+			String string = p.getSimpleName().toString();
+			if ( !StringUtil.isPropertyName( string ) ) {
+				return null;
+			}
+
+			TypeMirror returnType = t.getReturnType();
+			return returnType.accept( this, p );
+		}
+	}
 }

Added: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java	                        (rev 0)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,69 @@
+// $Id: XmlMetaEntity.java 18753 2010-02-09 21:29:34Z hardy.ferentschik $
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, 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();
+	}
+}
\ No newline at end of file

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -18,7 +18,6 @@
 package org.hibernate.jpamodelgen.xml;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -67,65 +66,61 @@
 		COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" );
 	}
 
-	private final String clazzName;
-	private final String packageName;
-	private final ImportContext importContext;
-	private final List<MetaAttribute> members = new ArrayList<MetaAttribute>();
-	private final TypeElement element;
-	private final Context context;
-	private final AccessTypeInformation accessTypeInfo;
+	protected final String clazzName;
+	protected final String packageName;
+	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 boolean isMetaComplete;
+	private Attributes attributes;
+	private EmbeddableAttributes embeddableAttributes;
+	protected AccessTypeInformation accessTypeInfo;
 
 	public XmlMetaEntity(Entity ormEntity, String packageName, TypeElement element, Context context) {
-		String className = ormEntity.getClazz();
+		this( ormEntity.getClazz(), packageName, element, context, ormEntity.isMetadataComplete() );
+		this.attributes = ormEntity.getAttributes();
+		this.embeddableAttributes = null;
+		// entities can be directly initialised
+		init();
+	}
+
+	protected XmlMetaEntity(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) {
+		this( mappedSuperclass.getClazz(), packageName, element, context, mappedSuperclass.isMetadataComplete() );
+		this.attributes = mappedSuperclass.getAttributes();
+		this.embeddableAttributes = null;
+	}
+
+	protected XmlMetaEntity(Embeddable embeddable, String packageName, TypeElement element, Context context) {
+		this( embeddable.getClazz(), packageName, element, context, embeddable.isMetadataComplete() );
+		this.attributes = null;
+		this.embeddableAttributes = embeddable.getAttributes();
+	}
+
+	private XmlMetaEntity(String clazz, String packageName, TypeElement element, Context context, Boolean metaComplete) {
+		String className = clazz;
 		if ( StringUtil.isFullyQualified( className ) ) {
 			// we have to extract the package name from the fqcn. default package name gets ignored
 			packageName = StringUtil.packageNameFromFqcn( className );
-			className = StringUtil.classNameFromFqcn( className );
+			className = StringUtil.classNameFromFqcn( clazz );
 		}
 		this.clazzName = className;
 		this.packageName = packageName;
 		this.context = context;
 		this.importContext = new ImportContextImpl( getPackageName() );
 		this.element = element;
-		this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
-		initIsMetaComplete( ormEntity.isMetadataComplete() );
-		parseAttributes( ormEntity.getAttributes() );
+		this.isMetaComplete = initIsMetaComplete( metaComplete );
 	}
 
-	public XmlMetaEntity(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) {
-		this.clazzName = mappedSuperclass.getClazz();
-		this.packageName = packageName;
-		this.context = context;
-		this.importContext = new ImportContextImpl( getPackageName() );
-		this.element = element;
+	protected void init() {
 		this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
-		initIsMetaComplete( mappedSuperclass.isMetadataComplete() );
-		parseAttributes( mappedSuperclass.getAttributes() );
-	}
-
-	public XmlMetaEntity(Embeddable embeddable, String packageName, TypeElement element, Context context) {
-		this.clazzName = embeddable.getClazz();
-		this.packageName = packageName;
-		this.context = context;
-		this.importContext = new ImportContextImpl( getPackageName() );
-		this.element = element;
-		this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
-		initIsMetaComplete( embeddable.isMetadataComplete() );
-		parseEmbeddableAttributes( embeddable.getAttributes() );
-	}
-
-	private void initIsMetaComplete(Boolean metadataComplete) {
-		if ( context.isPersistenceUnitCompletelyXmlConfigured() ) {
-			isMetaComplete = true;
-			return;
+		if ( attributes != null ) {
+			parseAttributes( attributes );
 		}
-		if ( Boolean.TRUE.equals( metadataComplete ) ) {
-			isMetaComplete = true;
-			return;
+		else {
+			parseEmbeddableAttributes( embeddableAttributes );
 		}
-		isMetaComplete = false;
 	}
 
 	public String getSimpleName() {
@@ -163,12 +158,28 @@
 	public TypeElement getTypeElement() {
 		return element;
 	}
-	
+
 	@Override
 	public boolean isMetaComplete() {
 		return isMetaComplete;
 	}
 
+	@Override
+	public String toString() {
+		final StringBuilder sb = new StringBuilder();
+		sb.append( "XmlMetaEntity" );
+		sb.append( "{accessTypeInfo=" ).append( accessTypeInfo );
+		sb.append( ", clazzName='" ).append( clazzName ).append( '\'' );
+		sb.append( ", members=" ).append( members );
+		sb.append( ", isMetaComplete=" ).append( isMetaComplete );
+		sb.append( '}' );
+		return sb.toString();
+	}
+
+	private boolean initIsMetaComplete(Boolean metadataComplete) {
+		return context.isPersistenceUnitCompletelyXmlConfigured() || Boolean.TRUE.equals( metadataComplete );
+	}
+
 	private String[] getCollectionType(String propertyName, String explicitTargetEntity, ElementKind expectedElementKind) {
 		String types[] = new String[2];
 		for ( Element elem : element.getEnclosedElements() ) {
@@ -221,7 +232,8 @@
 			if ( ElementKind.METHOD.equals( elem.getKind() ) ) {
 				name = StringUtil.getPropertyName( name );
 				mirror = ( ( ExecutableElement ) elem ).getReturnType();
-			} else {
+			}
+			else {
 				mirror = elem.asType();
 			}
 
@@ -244,6 +256,21 @@
 				case BOOLEAN: {
 					return "java.lang.Boolean";
 				}
+				case BYTE: {
+					return "java.lang.Byte";
+				}
+				case SHORT: {
+					return "java.lang.Short";
+				}
+				case CHAR: {
+					return "java.lang.Char";
+				}
+				case FLOAT: {
+					return "java.lang.Float";
+				}
+				case DOUBLE: {
+					return "java.lang.Double";
+				}
 				case DECLARED: {
 					return mirror.toString();
 				}
@@ -261,23 +288,9 @@
 		return null;
 	}
 
-	@Override
-	public String toString() {
-		final StringBuilder sb = new StringBuilder();
-		sb.append( "XmlMetaEntity" );
-		sb.append( "{accessTypeInfo=" ).append( accessTypeInfo );
-		sb.append( ", clazzName='" ).append( clazzName ).append( '\'' );
-		sb.append( ", members=" ).append( members );
-		sb.append( ", isMetaComplete=" ).append( isMetaComplete );
-		sb.append( '}' );
-		return sb.toString();
-	}
-
 	private void parseAttributes(Attributes attributes) {
 		XmlMetaSingleAttribute attribute;
-		if ( !attributes.getId().isEmpty() ) {
-			// TODO what do we do if there are more than one id nodes?
-			Id id = attributes.getId().get( 0 );
+		for ( Id id : attributes.getId() ) {
 			ElementKind elementKind = getElementKind( id.getAccess() );
 			String type = getType( id.getName(), null, elementKind );
 			if ( type != null ) {

Copied: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java (from rev 18753, jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java)
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java	                        (rev 0)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,74 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, 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.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+import org.hibernate.jpamodelgen.Context;
+import org.hibernate.jpamodelgen.MetaModelGenerationException;
+import org.hibernate.jpamodelgen.model.MetaAttribute;
+import org.hibernate.jpamodelgen.xml.jaxb.Basic;
+import org.hibernate.jpamodelgen.xml.jaxb.ElementCollection;
+import org.hibernate.jpamodelgen.xml.jaxb.EmbeddableAttributes;
+import org.hibernate.jpamodelgen.xml.jaxb.ManyToMany;
+import org.hibernate.jpamodelgen.xml.jaxb.ManyToOne;
+import org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass;
+import org.hibernate.jpamodelgen.xml.jaxb.OneToMany;
+import org.hibernate.jpamodelgen.xml.jaxb.OneToOne;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class XmlMetaMappedSuperClass extends XmlMetaEntity {
+	private boolean initialized;
+
+	public XmlMetaMappedSuperClass(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) {
+		super( mappedSuperclass, 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( "XmlMetaEntity" );
+		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();
+	}
+}
\ No newline at end of file


Property changes on: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -65,7 +65,7 @@
 		this.entityMappings = new ArrayList<EntityMappings>();
 	}
 
-	public void parsePersistenceXml() {
+	public void parseXml() {
 		collectAllEntityMappings();
 		determineDefaultAccessTypeAndMetaCompleteness();
 		determineXmlAccessTypes();
@@ -153,11 +153,7 @@
 				continue;
 			}
 
-			XmlMetaEntity metaEntity = new XmlMetaEntity(
-					embeddable, pkg, getXmlMappedType( fqcn ),
-					context
-			);
-
+			XmlMetaEntity metaEntity = new XmlMetaEmbeddable( embeddable, pkg, getXmlMappedType( fqcn ), context );
 			if ( context.containsMetaSuperclassOrEmbeddable( fqcn ) ) {
 				context.logMessage(
 						Diagnostic.Kind.WARNING,
@@ -184,9 +180,8 @@
 				continue;
 			}
 
-			XmlMetaEntity metaEntity = new XmlMetaEntity(
-					mappedSuperClass, pkg, getXmlMappedType( fqcn ),
-					context
+			XmlMetaEntity metaEntity = new XmlMetaMappedSuperClass(
+					mappedSuperClass, pkg, getXmlMappedType( fqcn ), context
 			);
 
 			if ( context.containsMetaSuperclassOrEmbeddable( fqcn ) ) {
@@ -297,12 +292,12 @@
 	}
 
 	private boolean xmlMappedTypeExists(String fullyQualifiedClassName) {
-		Elements utils = context.getProcessingEnvironment().getElementUtils();
+		Elements utils = context.getElementUtils();
 		return utils.getTypeElement( fullyQualifiedClassName ) != null;
 	}
 
 	private TypeElement getXmlMappedType(String fullyQualifiedClassName) {
-		Elements utils = context.getProcessingEnvironment().getElementUtils();
+		Elements utils = context.getElementUtils();
 		return utils.getTypeElement( fullyQualifiedClassName );
 	}
 

Added: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java	                        (rev 0)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,31 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.test.mixedmode;
+
+import javax.persistence.Embeddable;
+
+/**
+ * @author Hardy Ferentschik
+ */
+ at Embeddable
+public class Coordinates {
+	public float longitude;
+ 	public float latitude;
+}
+
+

Added: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java	                        (rev 0)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,73 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.test.mixedmode;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+/**
+ * @author Hardy Ferentschik
+ */
+ at Entity
+ at Access(AccessType.FIELD)
+public class Location {
+	@Id
+	private long id;
+	private String description;
+	// implicitly embedded
+	private Coordinates coordinates;
+	@Embedded
+	private ZeroCoordinates zeroCoordinates;
+
+	public Coordinates getCoordinates() {
+		return coordinates;
+	}
+
+	public void setCoordinates(Coordinates coordinates) {
+		this.coordinates = coordinates;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public ZeroCoordinates getZeroCoordinates() {
+		return zeroCoordinates;
+	}
+
+	public void setZeroCoordinates(ZeroCoordinates zeroCoordinates) {
+		this.zeroCoordinates = zeroCoordinates;
+	}	
+}
+
+

Modified: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -27,6 +27,7 @@
 import org.hibernate.jpamodelgen.test.util.TestUtil;
 
 import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAbsenceOfFieldInMetamodelFor;
+import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAttributeTypeInMetaModelFor;
 import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
 import static org.hibernate.jpamodelgen.test.util.TestUtil.assertPresenceOfFieldInMetamodelFor;
 
@@ -38,30 +39,60 @@
 	public void testDefaultAccessTypeApplied() {
 		assertMetamodelClassGeneratedFor( Vehicle.class );
 		assertMetamodelClassGeneratedFor( Car.class );
-		assertAbsenceOfFieldInMetamodelFor( Car.class, "horsePower" );
+
+		assertAbsenceOfFieldInMetamodelFor(
+				Car.class, "horsePower", "'horsePower' should not appear in metamodel since it does have no field."
+		);
 	}
 
 	@Test
 	public void testExplicitXmlConfiguredAccessTypeApplied() {
 		assertMetamodelClassGeneratedFor( Vehicle.class );
 		assertMetamodelClassGeneratedFor( Truck.class );
+
 		assertPresenceOfFieldInMetamodelFor(
 				Truck.class, "horsePower", "Property 'horsePower' has explicit access type and should be in metamodel"
 		);
+		assertAttributeTypeInMetaModelFor( Truck.class, "horsePower", Integer.class, "Wrong meta model type" );
 	}
 
 	@Test
 	public void testMixedConfiguration() {
 		assertMetamodelClassGeneratedFor( RentalCar.class );
 		assertMetamodelClassGeneratedFor( RentalCompany.class );
+
 		assertPresenceOfFieldInMetamodelFor(
 				RentalCar.class, "company", "Property 'company' should be included due to xml configuration"
 		);
+		assertAttributeTypeInMetaModelFor( RentalCar.class, "company", RentalCompany.class, "Wrong meta model type" );
+
 		assertPresenceOfFieldInMetamodelFor(
 				RentalCar.class, "insurance", "Property 'insurance' should be included since it is an embeddable"
 		);
+		assertAttributeTypeInMetaModelFor( RentalCar.class, "insurance", Insurance.class, "Wrong meta model type" );
 	}
 
+	@Test
+	public void testAccessTypeForXmlConfiguredEmbeddables() {
+		assertMetamodelClassGeneratedFor( Coordinates.class );
+		assertPresenceOfFieldInMetamodelFor(
+				Coordinates.class, "longitude", "field exists and should be in metamodel"
+		);
+		assertPresenceOfFieldInMetamodelFor( Coordinates.class, "latitude", "field exists and should be in metamodel" );
+
+		assertMetamodelClassGeneratedFor( ZeroCoordinates.class );
+		assertAbsenceOfFieldInMetamodelFor(
+				ZeroCoordinates.class,
+				"longitude",
+				"Field access should be used, but ZeroCoordinates does not define fields"
+		);
+		assertAbsenceOfFieldInMetamodelFor(
+				ZeroCoordinates.class,
+				"latitude",
+				"Field access should be used, but ZeroCoordinates does not define fields"
+		);
+	}
+
 	@Override
 	protected String getPackageNameOfTestSources() {
 		return MixedConfigurationTest.class.getPackage().getName();
@@ -74,6 +105,7 @@
 		ormFiles.add( dir + "/car.xml" );
 		ormFiles.add( dir + "/rentalcar.xml" );
 		ormFiles.add( dir + "/truck.xml" );
+		ormFiles.add( dir + "/coordinates.xml" );
 		return ormFiles;
 	}
 }
\ No newline at end of file

Added: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java	                        (rev 0)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,41 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.test.mixedmode;
+
+import javax.persistence.Embeddable;
+
+
+/**
+ * @author Hardy Ferentschik
+ */
+ at Embeddable
+public class ZeroCoordinates {
+	public float getLatitude() {
+		return 0f;
+	}
+
+	public void setLatitude(float latitude) {
+	}
+
+	public float getLongitude() {
+		return 0f;
+	}
+
+	public void setLongitude(float longitude) {
+	}
+}
\ No newline at end of file

Modified: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java	2010-02-11 02:42:15 UTC (rev 18772)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java	2010-02-11 02:43:51 UTC (rev 18773)
@@ -114,14 +114,18 @@
 
 	public static void assertAttributeTypeInMetaModelFor(Class<?> clazz, String fieldName, Class<?> expectedType, String errorString) {
 		Field field = getFieldFromMetamodelFor( clazz, fieldName );
-		assertNotNull( field, "Field " + fieldName + " should exist." );
+		assertNotNull( field, "Cannot find field '" + fieldName + "' in " + clazz.getName() );
 		ParameterizedType type = ( ParameterizedType ) field.getGenericType();
 		Type actualType = type.getActualTypeArguments()[1];
 		if ( expectedType.isArray() ) {
 			expectedType = expectedType.getComponentType();
 			actualType = ( ( GenericArrayType ) actualType ).getGenericComponentType();
 		}
-		assertEquals( actualType, expectedType, errorString );
+		assertEquals(
+				actualType,
+				expectedType,
+				"Types do not match: " + errorString
+		);
 	}
 
 	public static void assertMapAttributesInMetaModelFor(Class<?> clazz, String fieldName, Class<?> expectedMapKey, Class<?> expectedMapValue, String errorString) {
@@ -180,13 +184,13 @@
 
 	private static class MetaModelFilenameFilter implements FileFilter {
 		@Override
-		public boolean accept(File pathname) {
-			if ( pathname.isDirectory() ) {
+		public boolean accept(File pathName) {
+			if ( pathName.isDirectory() ) {
 				return true;
 			}
 			else {
-				return pathname.getAbsolutePath().endsWith( "_.java" )
-						|| pathname.getAbsolutePath().endsWith( "_.class" );
+				return pathName.getAbsolutePath().endsWith( "_.java" )
+						|| pathName.getAbsolutePath().endsWith( "_.class" );
 			}
 		}
 	}

Copied: jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml (from rev 18734, jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/car.xml)
===================================================================
--- jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml	                        (rev 0)
+++ jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml	2010-02-11 02:43:51 UTC (rev 18773)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
+                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
+                 version="2.0"
+        >
+    <!-- no implicit or explicit access configured here -->
+    <embeddable class="org.hibernate.jpamodelgen.test.mixedmode.Coordinates">
+        <attributes>
+            <basic name="longitude"/>
+            <basic name="latitude"/>
+        </attributes>
+    </embeddable>
+    <embeddable class="org.hibernate.jpamodelgen.test.mixedmode.ZeroCoordinates">
+        <attributes>
+            <basic name="longitude"/>
+            <basic name="latitude"/>
+        </attributes>
+    </embeddable>
+</entity-mappings>
+



More information about the hibernate-commits mailing list