Author: epbernard
Date: 2009-07-08 19:25:41 -0400 (Wed, 08 Jul 2009)
New Revision: 17055
Added:
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/ClassWriter.java
jpamodelgen/trunk/test/src/main/java/model/Detail.java
Modified:
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/Context.java
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/JPAMetaModelEntityProcessor.java
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/annotation/MetaEntity.java
jpamodelgen/trunk/test/src/main/java/model/Item.java
jpamodelgen/trunk/test/src/test/java/tests/AccessTypeTest.java
Log:
Add support for default access type for embeddable objects
Added:
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/ClassWriter.java
===================================================================
---
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/ClassWriter.java
(rev 0)
+++
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/ClassWriter.java 2009-07-08
23:25:41 UTC (rev 17055)
@@ -0,0 +1,123 @@
+package org.hibernate.jpa.metamodel.ap;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.FilerException;
+import javax.annotation.Generated;
+import javax.tools.FileObject;
+import javax.tools.Diagnostic;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ClassWriter {
+
+ public static void writeFile(IMetaEntity entity, ProcessingEnvironment processingEnv,
Context context) {
+ try {
+ String metaModelPackage = entity.getPackageName();
+
+ StringBuffer body = generateBody( entity, context );
+
+ FileObject fo = processingEnv.getFiler().createSourceFile(
+ metaModelPackage + "." + entity.getSimpleName() + "_"
+ );
+ OutputStream os = fo.openOutputStream();
+ PrintWriter pw = new PrintWriter( os );
+
+ pw.println( "package " + metaModelPackage + ";" );
+
+ pw.println();
+
+ pw.println( entity.generateImports() );
+
+ pw.println( body );
+
+ pw.flush();
+ pw.close();
+
+ }
+ catch ( FilerException filerEx ) {
+ processingEnv.getMessager().printMessage(
+ Diagnostic.Kind.ERROR,
+ "Problem with Processing Environment Filer: "
+ + filerEx.getMessage()
+ );
+ }
+ catch ( IOException ioEx ) {
+ processingEnv.getMessager().printMessage(
+ Diagnostic.Kind.ERROR,
+ "Problem opening file to write MetaModel for " + entity.getSimpleName()
+ + ioEx.getMessage()
+ );
+ }
+ }
+
+ /**
+ * Generate everything after import statements.
+ *
+ * @param entity The meta entity for which to write the body
+ *
+ * @return body content
+ */
+ private static StringBuffer generateBody(IMetaEntity entity, Context context) {
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = null;
+ try {
+
+ pw = new PrintWriter( sw );
+
+ pw.println( "@" + entity.importType( Generated.class.getName() ) +
"(\"JPA MetaModel for " + entity.getQualifiedName() + "\")"
);
+
+ pw.println( "@" + entity.importType(
"javax.persistence.metamodel.StaticMetamodel" ) + "(" +
entity.getSimpleName() + ".class)" );
+
+
+
+ printClassDeclaration( entity, pw, context );
+
+ pw.println();
+
+ List<IMetaAttribute> members = entity.getMembers();
+
+ for ( IMetaAttribute metaMember : members ) {
+ pw.println( " " + metaMember.getDeclarationString() );
+ }
+ pw.println();
+ pw.println( "}" );
+ return sw.getBuffer();
+ }
+ finally {
+ if ( pw != null ) {
+ pw.close();
+ }
+ }
+ }
+
+ private static void printClassDeclaration(IMetaEntity entity, PrintWriter pw, Context
context) {
+ pw.print( "public abstract class " + entity.getSimpleName() + "_"
);
+
+ final TypeMirror superClass = entity.getTypeElement().getSuperclass();
+ //superclass of Object is of NoType which returns some other kind
+ String superclassDeclaration = "";
+ if (superClass.getKind() == TypeKind.DECLARED ) {
+ //F..king Ch...t Have those people used their horrible APIs even once?
+ final Element superClassElement = ( ( DeclaredType ) superClass ).asElement();
+ String superClassName = ( ( TypeElement ) superClassElement
).getQualifiedName().toString();
+ if ( context.getMetaEntitiesToProcess().containsKey( superClassName )
+ || context.getMetaSuperclassAndEmbeddableToProcess().containsKey( superClassName ) )
{
+ pw.print( " extends " + superClassName + "_" );
+ }
+ }
+
+ pw.println( " {" );
+ }
+}
Modified:
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/Context.java
===================================================================
---
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/Context.java 2009-07-08
18:11:20 UTC (rev 17054)
+++
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/Context.java 2009-07-08
23:25:41 UTC (rev 17055)
@@ -2,16 +2,38 @@
import java.util.Map;
import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
import javax.lang.model.element.TypeElement;
import javax.persistence.AccessType;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.tools.Diagnostic;
+import org.hibernate.jpa.metamodel.ap.annotation.MetaEntity;
+
/**
* @author Emmanuel Bernard
*/
public class Context {
//used to cache access types
private Map<TypeElement, AccessType> accessTypes = new
HashMap<TypeElement,AccessType>();
+ private Set<String> elementsAlreadyProcessed = new HashSet<String>();
+ private ProcessingEnvironment pe;
+ private final Map<String, IMetaEntity> metaEntitiesToProcess = new
HashMap<String, IMetaEntity>();
+ private final Map<String, IMetaEntity> metaSuperclassAndEmbeddableToProcess = new
HashMap<String, IMetaEntity>();
+ public Context(ProcessingEnvironment pe) {
+ this.pe = pe;
+ }
+
+ public Map<String, IMetaEntity> getMetaEntitiesToProcess() {
+ return metaEntitiesToProcess;
+ }
+
+ public Map<String, IMetaEntity> getMetaSuperclassAndEmbeddableToProcess() {
+ return metaSuperclassAndEmbeddableToProcess;
+ }
+
public void addAccessType(TypeElement element, AccessType accessType) {
accessTypes.put( element, accessType );
}
@@ -19,4 +41,20 @@
public Map<TypeElement, AccessType> getAccessTypes() {
return accessTypes;
}
+
+ public Set<String> getElementsAlreadyProcessed() {
+ return elementsAlreadyProcessed;
+ }
+
+ //only process Embeddable or Superclass
+ //does not work for Entity (risk of circularity)
+ public void processElement(TypeElement element, AccessType
defaultAccessTypeForHierarchy) {
+ if ( elementsAlreadyProcessed.contains( element.getQualifiedName().toString() ) ) {
+ pe.getMessager().printMessage( Diagnostic.Kind.WARNING, "Element already
processed (ignoring): " + element );
+ return;
+ }
+
+ ClassWriter.writeFile( new MetaEntity( pe, element, this, defaultAccessTypeForHierarchy
), pe, this );
+ elementsAlreadyProcessed.add( element.getQualifiedName().toString() );
+ }
}
Modified:
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/JPAMetaModelEntityProcessor.java
===================================================================
---
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/JPAMetaModelEntityProcessor.java 2009-07-08
18:11:20 UTC (rev 17054)
+++
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/JPAMetaModelEntityProcessor.java 2009-07-08
23:25:41 UTC (rev 17055)
@@ -57,18 +57,16 @@
private static final String PATH_SEPARATOR = "/";
private static final String PERSISTENCE_XML = "/META-INF/persistence.xml";
private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS =
Boolean.TRUE;
-
- private final Map<String, IMetaEntity> metaEntities = new HashMap<String,
IMetaEntity>();
- private boolean xmlProcessed = false;
private static final String ENTITY_ANN = javax.persistence.Entity.class.getName();
private static final String MAPPED_SUPERCLASS_ANN = MappedSuperclass.class.getName();
private static final String EMBEDDABLE_ANN = Embeddable.class.getName();
- private Context context = new Context();
+ private boolean xmlProcessed = false;
+ private Context context;
-
public void init(ProcessingEnvironment env) {
super.init( env );
+ context = new Context(env);
processingEnv.getMessager().printMessage( Diagnostic.Kind.NOTE, "Init Processor
" + this );
}
@@ -107,11 +105,22 @@
}
private void createMetaModelClasses() {
- for ( IMetaEntity entity : metaEntities.values() ) {
+ for ( IMetaEntity entity : context.getMetaEntitiesToProcess().values() ) {
processingEnv.getMessager()
.printMessage( Diagnostic.Kind.NOTE, "Writing meta model for " + entity
);
- writeFile( entity );
+ ClassWriter.writeFile( entity, processingEnv, context );
}
+
+ //process left over, in most cases is empty
+ for ( String className : context.getElementsAlreadyProcessed() ) {
+ context.getMetaSuperclassAndEmbeddableToProcess().remove( className );
+ }
+
+ for ( IMetaEntity entity : context.getMetaSuperclassAndEmbeddableToProcess().values() )
{
+ processingEnv.getMessager()
+ .printMessage( Diagnostic.Kind.NOTE, "Writing meta model for " + entity
);
+ ClassWriter.writeFile( entity, processingEnv, context );
+ }
}
private boolean hostJPAAnnotations(Set<? extends TypeElement> annotations) {
@@ -167,13 +176,13 @@
entity, packageName, utils.getTypeElement( fullyQualifiedClassName ), context
);
- if ( metaEntities.containsKey( fullyQualifiedClassName ) ) {
+ if ( context.getMetaEntitiesToProcess().containsKey( fullyQualifiedClassName ) ) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " was already processed once. Skipping second
occurance."
);
}
- metaEntities.put( fullyQualifiedClassName, metaEntity );
+ context.getMetaEntitiesToProcess().put( fullyQualifiedClassName, metaEntity );
}
}
@@ -187,13 +196,13 @@
embeddable, packageName, utils.getTypeElement( fullyQualifiedClassName )
);
- if ( metaEntities.containsKey( fullyQualifiedClassName ) ) {
+ if ( context.getMetaSuperclassAndEmbeddableToProcess().containsKey(
fullyQualifiedClassName ) ) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " was already processed once. Skipping second
occurance."
);
}
- metaEntities.put( fullyQualifiedClassName, metaEntity );
+ context.getMetaSuperclassAndEmbeddableToProcess().put( fullyQualifiedClassName,
metaEntity );
}
}
@@ -205,118 +214,23 @@
for ( AnnotationMirror mirror : annotationMirrors ) {
final String annotationType = mirror.getAnnotationType().toString();
- if ( element.getKind() == ElementKind.CLASS &&
- ( annotationType.equals( ENTITY_ANN )
- || annotationType.equals( MAPPED_SUPERCLASS_ANN )
- || annotationType.equals( EMBEDDABLE_ANN )
- ) ) {
- MetaEntity metaEntity = new MetaEntity( processingEnv, ( TypeElement ) element,
context );
+ if ( element.getKind() == ElementKind.CLASS ) {
+ if ( annotationType.equals( ENTITY_ANN ) ) {
+ MetaEntity metaEntity = new MetaEntity( processingEnv, ( TypeElement ) element,
context );
+ // TODO instead of just adding the entity we have to do some merging.
+ context.getMetaEntitiesToProcess().put( metaEntity.getQualifiedName(), metaEntity
);
+ }
+ else if ( annotationType.equals( MAPPED_SUPERCLASS_ANN )
+ || annotationType.equals( EMBEDDABLE_ANN ) ) {
+ MetaEntity metaEntity = new MetaEntity( processingEnv, ( TypeElement ) element,
context );
- // TODO instead of just adding the entity we have to do some merging.
- metaEntities.put( metaEntity.getQualifiedName(), metaEntity );
+ // TODO instead of just adding the entity we have to do some merging.
+ context.getMetaSuperclassAndEmbeddableToProcess().put(
metaEntity.getQualifiedName(), metaEntity );
+ }
}
}
}
- private void writeFile(IMetaEntity entity) {
- try {
- String metaModelPackage = entity.getPackageName();
-
- StringBuffer body = generateBody( entity );
-
- FileObject fo = processingEnv.getFiler().createSourceFile(
- metaModelPackage + "." + entity.getSimpleName() + "_"
- );
- OutputStream os = fo.openOutputStream();
- PrintWriter pw = new PrintWriter( os );
-
- pw.println( "package " + metaModelPackage + ";" );
-
- pw.println();
-
- pw.println( entity.generateImports() );
-
- pw.println( body );
-
- pw.flush();
- pw.close();
-
- }
- catch ( FilerException filerEx ) {
- processingEnv.getMessager().printMessage(
- Diagnostic.Kind.ERROR,
- "Problem with Processing Environment Filer: "
- + filerEx.getMessage()
- );
- }
- catch ( IOException ioEx ) {
- processingEnv.getMessager().printMessage(
- Diagnostic.Kind.ERROR,
- "Problem opening file to write MetaModel for " + entity.getSimpleName()
- + ioEx.getMessage()
- );
- }
- }
-
- /**
- * Generate everything after import statements.
- *
- * @param entity The meta entity for which to write the body
- *
- * @return body content
- */
- private StringBuffer generateBody(IMetaEntity entity) {
-
- StringWriter sw = new StringWriter();
- PrintWriter pw = null;
- try {
-
- pw = new PrintWriter( sw );
-
- pw.println( "@" + entity.importType( Generated.class.getName() ) +
"(\"JPA MetaModel for " + entity.getQualifiedName() + "\")"
);
-
- pw.println( "@" + entity.importType(
"javax.persistence.metamodel.StaticMetamodel" ) + "(" +
entity.getSimpleName() + ".class)" );
-
-
-
- printClassDeclaration( entity, pw );
-
- pw.println();
-
- List<IMetaAttribute> members = entity.getMembers();
-
- for ( IMetaAttribute metaMember : members ) {
- pw.println( " " + metaMember.getDeclarationString() );
- }
- pw.println();
- pw.println( "}" );
- return sw.getBuffer();
- }
- finally {
- if ( pw != null ) {
- pw.close();
- }
- }
- }
-
- private void printClassDeclaration(IMetaEntity entity, PrintWriter pw) {
- pw.print( "public abstract class " + entity.getSimpleName() + "_"
);
-
- final TypeMirror superClass = entity.getTypeElement().getSuperclass();
- //superclass of Object is of NoType which returns some other kind
- String superclassDeclaration = "";
- if (superClass.getKind() == TypeKind.DECLARED ) {
- //F..king Ch...t Have those people used their horrible APIs even once?
- final Element superClassElement = ( ( DeclaredType ) superClass ).asElement();
- String superClassName = ( ( TypeElement ) superClassElement
).getQualifiedName().toString();
- if ( metaEntities.containsKey( superClassName ) ) {
- pw.print( " extends " + superClassName + "_" );
- }
- }
-
- pw.println( " {" );
- }
-
private InputStream getInputStreamForResource(String resource) {
String pkg = getPackage( resource );
String name = getRelativeName( resource );
Modified:
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/annotation/MetaEntity.java
===================================================================
---
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/annotation/MetaEntity.java 2009-07-08
18:11:20 UTC (rev 17054)
+++
jpamodelgen/trunk/generator/src/main/java/org/hibernate/jpa/metamodel/ap/annotation/MetaEntity.java 2009-07-08
23:25:41 UTC (rev 17055)
@@ -23,6 +23,8 @@
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
+import javax.persistence.Embedded;
+import javax.persistence.Embeddable;
import javax.tools.Diagnostic.Kind;
import javax.tools.Diagnostic;
@@ -40,6 +42,7 @@
final ImportContext importContext;
private Context context;
+ private AccessType defaultAccessTypeForHierarchy;
public MetaEntity(ProcessingEnvironment pe, TypeElement element, Context context) {
this.element = element;
@@ -48,6 +51,11 @@
this.context = context;
}
+ public MetaEntity(ProcessingEnvironment pe, TypeElement element, Context context,
AccessType accessType) {
+ this(pe, element, context);
+ this.defaultAccessTypeForHierarchy = accessType;
+ }
+
public String getSimpleName() {
return element.getSimpleName().toString();
}
@@ -113,8 +121,17 @@
}
private boolean useFields() {
+ //default strategy has more power than local discovery
+ if ( this.defaultAccessTypeForHierarchy != null ) {
+ return defaultAccessTypeForHierarchy == AccessType.FIELD;
+ }
+
+ //get local strategy
AccessType accessType = getAccessTypeForClass( element );
- if (accessType != null) return accessType == AccessType.FIELD;
+ if (accessType != null) {
+ this.defaultAccessTypeForHierarchy = accessType;
+ return accessType == AccessType.FIELD;
+ }
//we dont' know
//if an enity go up
@@ -127,18 +144,25 @@
if ( superClass.getAnnotation( Entity.class ) != null ) {
//FIXME make it work for XML
accessType = getAccessTypeForClass(superClass);
- if ( accessType != null ) return accessType == AccessType.FIELD;
+ if ( accessType != null ) {
+ this.defaultAccessTypeForHierarchy = accessType;
+ return accessType == AccessType.FIELD;
+ }
}
else if ( superClass.getAnnotation( MappedSuperclass.class ) != null ) {
accessType = getAccessTypeForClass(superClass);
- if ( accessType != null ) return accessType == AccessType.FIELD;
+ if ( accessType != null ) {
+ this.defaultAccessTypeForHierarchy = accessType;
+ return accessType == AccessType.FIELD;
+ }
}
}
}
while ( superClass != null );
//this is a subclass so caching is OK
+ this.defaultAccessTypeForHierarchy = accessType;
context.addAccessType( this.element, AccessType.PROPERTY );
- return false;
+ return false; //default to getter
}
private AccessType getAccessTypeForClass(TypeElement searchedElement) {
@@ -175,7 +199,6 @@
}
}
}
- pe.getMessager().printMessage( Diagnostic.Kind.NOTE, "No access type found: "
+ searchedElement );
return null;
}
@@ -223,21 +246,28 @@
@Override
- public MetaAttribute visitDeclared(DeclaredType t, Element p) {
+ public MetaAttribute visitDeclared(DeclaredType t, Element element) {
//FIXME consider XML
- if ( p.getAnnotation( Transient.class ) == null ) {
- TypeElement e = ( TypeElement ) pe.getTypeUtils().asElement( t );
- String collection = COLLECTIONS.get( e.getQualifiedName().toString() ); // WARNING:
.toString() is necessary here since Name equals does not compare to String
+ if ( element.getAnnotation( Transient.class ) == null ) {
+ TypeElement returnedElement = ( TypeElement ) pe.getTypeUtils().asElement( t );
+ String collection = COLLECTIONS.get( returnedElement.getQualifiedName().toString() );
// WARNING: .toString() is necessary here since Name equals does not compare to String
+ //FIXME collection of element
if ( collection != null ) {
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
- return new MetaMap( parent, p, collection, getKeyType( t ), getElementType( t ) );
+ return new MetaMap( parent, element, collection, getKeyType( t ), getElementType( t
) );
}
else {
- return new MetaCollection( parent, p, collection, getElementType( t ) );
+ return new MetaCollection( parent, element, collection, getElementType( t ) );
}
}
else {
- return new MetaSingleAttribute( parent, p, e.getQualifiedName().toString() );
+ //FIXME Consider XML
+ if ( element.getAnnotation( Embedded.class ) != null
+ || returnedElement.getAnnotation( Embeddable.class ) != null ) {
+ this.parent.context.processElement( returnedElement,
+ this.parent.defaultAccessTypeForHierarchy );
+ }
+ return new MetaSingleAttribute( parent, element,
returnedElement.getQualifiedName().toString() );
}
}
else {
Added: jpamodelgen/trunk/test/src/main/java/model/Detail.java
===================================================================
--- jpamodelgen/trunk/test/src/main/java/model/Detail.java (rev
0)
+++ jpamodelgen/trunk/test/src/main/java/model/Detail.java 2009-07-08 23:25:41 UTC (rev
17055)
@@ -0,0 +1,38 @@
+package model;
+
+import javax.persistence.Embeddable;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Embeddable
+public class Detail {
+ Integer length;
+ Integer width;
+ Integer height;
+ Integer nonPersistent;
+
+ public Integer getLength() {
+ return length;
+ }
+
+ public void setLength(Integer length) {
+ this.length = length;
+ }
+
+ public Integer getWidth() {
+ return width;
+ }
+
+ public void setWidth(Integer width) {
+ this.width = width;
+ }
+
+ public Integer getHeight() {
+ return height;
+ }
+
+ public void setHeight(Integer height) {
+ this.height = height;
+ }
+}
Modified: jpamodelgen/trunk/test/src/main/java/model/Item.java
===================================================================
--- jpamodelgen/trunk/test/src/main/java/model/Item.java 2009-07-08 18:11:20 UTC (rev
17054)
+++ jpamodelgen/trunk/test/src/main/java/model/Item.java 2009-07-08 23:25:41 UTC (rev
17055)
@@ -19,6 +19,8 @@
Order _order;
+ Detail detail;
+
@Id
public long getId() {
return _id;
@@ -58,6 +60,12 @@
public Map<String, Order> getNamedOrders() {
return null;
}
-
-
+
+ public Detail getDetail() {
+ return detail;
+ }
+
+ public void setDetail(Detail detail) {
+ this.detail = detail;
+ }
}
Modified: jpamodelgen/trunk/test/src/test/java/tests/AccessTypeTest.java
===================================================================
--- jpamodelgen/trunk/test/src/test/java/tests/AccessTypeTest.java 2009-07-08 18:11:20 UTC
(rev 17054)
+++ jpamodelgen/trunk/test/src/test/java/tests/AccessTypeTest.java 2009-07-08 23:25:41 UTC
(rev 17055)
@@ -22,7 +22,12 @@
absenceOfField( "model.Customer_", "nonPersistent" );
}
+ @Test
+ public void testDefaultAccessTypeForEmbeddable() throws Exception{
+ absenceOfField( "model.Detail_", "nonPersistent " );
+ }
+
private void absenceOfField(String className, String fieldName) throws
ClassNotFoundException {
Class<?> user_ = Class.forName( className );
try {