METAGEN-2

Added support for arrays. Arrays are now added to the metamodel as SingularAttribute.
We don't, however, cover the case yet where there is a @*ToMany annotation on the array
This commit is contained in:
Hardy Ferentschik 2009-11-04 16:01:22 +00:00 committed by Strong Liu
parent 95da451ce7
commit 0e9f97ce2f
9 changed files with 196 additions and 90 deletions

View File

@ -17,26 +17,26 @@
*/
package org.hibernate.jpamodelgen;
import java.io.IOException;
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.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.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
/**
* @author Emmanuel Bernard
*/
public class ClassWriter {
public static void writeFile(MetaEntity entity, ProcessingEnvironment processingEnv, Context context) {
try {
String metaModelPackage = entity.getPackageName();
@ -89,21 +89,13 @@ public class ClassWriter {
StringWriter sw = new StringWriter();
PrintWriter pw = null;
try {
pw = new PrintWriter( sw );
// we cannot use add @Generated into the metamodel class since this would not work in a JDK 5 environment
//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<MetaAttribute> members = entity.getMembers();
for ( MetaAttribute metaMember : members ) {
pw.println( " " + metaMember.getDeclarationString() );
}
@ -124,16 +116,15 @@ public class ClassWriter {
final TypeMirror superClass = entity.getTypeElement().getSuperclass();
//superclass of Object is of NoType which returns some other kind
String superclassDeclaration = "";
if (superClass.getKind() == TypeKind.DECLARED ) {
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.print( " extends " + superClassName + "_" );
}
}
pw.println( " {" );
}
}

View File

@ -25,38 +25,37 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Embedded;
import javax.persistence.Embeddable;
import javax.persistence.Access;
import javax.persistence.ElementCollection;
import javax.tools.Diagnostic.Kind;
import javax.tools.Diagnostic;
import org.hibernate.jpamodelgen.MetaEntity;
import org.hibernate.jpamodelgen.MetaAttribute;
import org.hibernate.jpamodelgen.Context;
import org.hibernate.jpamodelgen.ImportContext;
import org.hibernate.jpamodelgen.ImportContextImpl;
import org.hibernate.jpamodelgen.MetaAttribute;
import org.hibernate.jpamodelgen.MetaEntity;
import org.hibernate.jpamodelgen.TypeUtils;
import org.hibernate.jpamodelgen.Context;
/**
*
* @author Max Andersen
* @author Hardy Ferentschik
* @author Emmanuel Bernard
@ -80,7 +79,7 @@ public class AnnotationMetaEntity implements MetaEntity {
}
public AnnotationMetaEntity(ProcessingEnvironment pe, TypeElement element, Context context, AccessType accessType) {
this(pe, element, context);
this( pe, element, context );
this.defaultAccessTypeForHierarchy = accessType;
}
@ -88,10 +87,6 @@ public class AnnotationMetaEntity implements MetaEntity {
return element.getSimpleName().toString();
}
public Element getOriginalElement() {
return element;
}
public String getQualifiedName() {
return element.getQualifiedName().toString();
}
@ -112,9 +107,9 @@ public class AnnotationMetaEntity implements MetaEntity {
addPersistentMembers( membersFound, elementAccessType, methodsOfClass, AccessType.PROPERTY );
//process superclasses
for(TypeElement superclass = TypeUtils.getSuperclass(element) ;
superclass != null ;
superclass = TypeUtils.getSuperclass( superclass ) ) {
for ( TypeElement superclass = TypeUtils.getSuperclass( element );
superclass != null;
superclass = TypeUtils.getSuperclass( superclass ) ) {
if ( superclass.getAnnotation( Entity.class ) != null ) {
break; //will be handled or has been handled already
}
@ -123,11 +118,6 @@ public class AnnotationMetaEntity implements MetaEntity {
context.processElement( superclass, defaultAccessTypeForHierarchy );
}
}
//this is valid to not have properties (ie subentities)
// if ( membersFound.size() == 0 ) {
// pe.getMessager().printMessage( Kind.WARNING, "No properties found on " + element, element );
// }
return membersFound;
}
@ -136,10 +126,8 @@ public class AnnotationMetaEntity implements MetaEntity {
AccessType elementAccessType,
List<? extends Element> membersOfClass,
AccessType membersKind) {
pe.getMessager()
.printMessage( Kind.NOTE, "Scanning " + membersOfClass.size() + " " + membersKind + " for " + element.toString() );
AccessType explicitAccessType;
if (elementAccessType == membersKind) {
if ( elementAccessType == membersKind ) {
//all membersKind considered
explicitAccessType = null;
}
@ -149,27 +137,22 @@ public class AnnotationMetaEntity implements MetaEntity {
}
for ( Element memberOfClass : membersOfClass ) {
AnnotationMetaAttribute result = memberOfClass.asType().accept( new TypeVisitor( this, explicitAccessType ),
memberOfClass
);
TypeVisitor visitor = new TypeVisitor( this, explicitAccessType );
AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass );
if ( result != null ) {
membersFound.add( result );
}
//EBE not sure why?
// else {
// pe.getMessager().printMessage( Kind.WARNING, "Could not find valid info for JPA property", mymember );
// }
}
}
private AccessType getAccessTypeForElement() {
//get local strategy
AccessType accessType = getAccessTypeForClass(element);
if (accessType == null) {
AccessType accessType = getAccessTypeForClass( element );
if ( accessType == null ) {
accessType = this.defaultAccessTypeForHierarchy;
}
if (accessType == null) {
if ( accessType == null ) {
//we dont' know
//if an enity go up
//
@ -179,13 +162,13 @@ public class AnnotationMetaEntity implements MetaEntity {
TypeElement superClass = element;
do {
superClass = TypeUtils.getSuperclass( superClass );
if (superClass != null) {
if ( superClass != null ) {
if ( superClass.getAnnotation( Entity.class ) != null
|| superClass.getAnnotation( MappedSuperclass.class ) != null ) {
//FIXME make it work for XML
AccessType superClassAccessType = getAccessTypeForClass(superClass);
AccessType superClassAccessType = getAccessTypeForClass( superClass );
//we've reach the root entity and resolved Ids
if ( superClassAccessType != null && defaultAccessTypeForHierarchy != null) {
if ( superClassAccessType != null && defaultAccessTypeForHierarchy != null ) {
break; //we've found it
}
}
@ -212,11 +195,12 @@ public class AnnotationMetaEntity implements MetaEntity {
pe.getMessager().printMessage( Diagnostic.Kind.NOTE, "check class" + searchedElement );
AccessType accessType = context.getAccessType( searchedElement );
if (defaultAccessTypeForHierarchy == null) {
if ( defaultAccessTypeForHierarchy == null ) {
this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( searchedElement );
}
if ( accessType != null ) {
pe.getMessager().printMessage( Diagnostic.Kind.NOTE, "Found in cache" + searchedElement + ":" + accessType );
pe.getMessager()
.printMessage( Diagnostic.Kind.NOTE, "Found in cache" + searchedElement + ":" + accessType );
return accessType;
}
@ -226,14 +210,15 @@ public class AnnotationMetaEntity implements MetaEntity {
*/
final Access accessAnn = searchedElement.getAnnotation( Access.class );
AccessType forcedAccessType = accessAnn != null ? accessAnn.value() : null;
if ( forcedAccessType != null) {
pe.getMessager().printMessage( Diagnostic.Kind.NOTE, "access type " + searchedElement + ":" + forcedAccessType );
if ( forcedAccessType != null ) {
pe.getMessager()
.printMessage( Diagnostic.Kind.NOTE, "access type " + searchedElement + ":" + forcedAccessType );
context.addAccessType( searchedElement, forcedAccessType );
}
//continue nevertheless to check if we are root and if defaultAccessTypeForHierarchy
//should be overridden
if ( forcedAccessType == null || defaultAccessTypeForHierarchy == null) {
if ( forcedAccessType == null || defaultAccessTypeForHierarchy == null ) {
List<? extends Element> myMembers = searchedElement.getEnclosedElements();
for ( Element subElement : myMembers ) {
List<? extends AnnotationMirror> entityAnnotations =
@ -252,8 +237,10 @@ public class AnnotationMetaEntity implements MetaEntity {
if ( kind == ElementKind.FIELD || kind == ElementKind.METHOD ) {
accessType = kind == ElementKind.FIELD ? AccessType.FIELD : AccessType.PROPERTY;
//FIXME enlever in niveau
if (defaultAccessTypeForHierarchy == null) {
this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( searchedElement );
if ( defaultAccessTypeForHierarchy == null ) {
this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy(
searchedElement
);
//we've discovered the class hierarchy, let's cache it
if ( defaultAccessTypeForHierarchy == null ) {
this.defaultAccessTypeForHierarchy = accessType;
@ -262,9 +249,11 @@ public class AnnotationMetaEntity implements MetaEntity {
//context.addAccessTypeForHierarchy( element, defaultAccessTypeForHierarchy );
}
}
if ( forcedAccessType == null) {
if ( forcedAccessType == null ) {
context.addAccessType( searchedElement, accessType );
pe.getMessager().printMessage( Diagnostic.Kind.NOTE, "access type " + searchedElement + ":" + accessType );
pe.getMessager().printMessage(
Diagnostic.Kind.NOTE, "access type " + searchedElement + ":" + accessType
);
return accessType;
}
else {
@ -323,10 +312,20 @@ public class AnnotationMetaEntity implements MetaEntity {
}
}
@Override
public AnnotationMetaAttribute visitArray(ArrayType t, Element element) {
if ( isPersistent( element ) ) {
return new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) );
}
else {
return null;
}
}
private boolean isPersistent(Element element) {
//FIXME consider XML
boolean correctAccessType = false;
if (this.explicitAccessType == null) {
if ( this.explicitAccessType == null ) {
correctAccessType = true;
}
else {
@ -342,7 +341,6 @@ public class AnnotationMetaEntity implements MetaEntity {
}
@Override
public AnnotationMetaAttribute visitDeclared(DeclaredType t, Element element) {
//FIXME consider XML
@ -354,12 +352,17 @@ public class AnnotationMetaEntity implements MetaEntity {
//collection of element
if ( element.getAnnotation( ElementCollection.class ) != null ) {
final TypeMirror collectionType = t.getTypeArguments().get( 0 );
final TypeElement collectionElement = ( TypeElement ) pe.getTypeUtils().asElement( collectionType );
this.parent.context.processElement( collectionElement,
this.parent.defaultAccessTypeForElement );
final TypeElement collectionElement = ( TypeElement ) pe.getTypeUtils()
.asElement( collectionType );
this.parent.context.processElement(
collectionElement,
this.parent.defaultAccessTypeForElement
);
}
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
return new AnnotationMetaMap( parent, element, collection, getKeyType( t ), getElementType( t ) );
return new AnnotationMetaMap(
parent, element, collection, getKeyType( t ), getElementType( t )
);
}
else {
return new AnnotationMetaCollection( parent, element, collection, getElementType( t ) );
@ -369,10 +372,14 @@ public class AnnotationMetaEntity implements MetaEntity {
//FIXME Consider XML
if ( element.getAnnotation( Embedded.class ) != null
|| returnedElement.getAnnotation( Embeddable.class ) != null ) {
this.parent.context.processElement( returnedElement,
this.parent.defaultAccessTypeForElement );
this.parent.context.processElement(
returnedElement,
this.parent.defaultAccessTypeForElement
);
}
return new AnnotationMetaSingleAttribute( parent, element, returnedElement.getQualifiedName().toString() );
return new AnnotationMetaSingleAttribute(
parent, element, returnedElement.getQualifiedName().toString()
);
}
}
else {
@ -380,7 +387,6 @@ public class AnnotationMetaEntity implements MetaEntity {
}
}
@Override
public AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) {
String string = p.getSimpleName().toString();
@ -421,7 +427,6 @@ public class AnnotationMetaEntity implements MetaEntity {
return t.getTypeArguments().get( 0 ).toString();
}
private String getElementType(DeclaredType declaredType) {
if ( declaredType.getTypeArguments().size() == 1 ) {
return declaredType.getTypeArguments().get( 0 ).toString();

View File

@ -17,12 +17,11 @@
*/
package org.hibernate.jpamodelgen.annotation;
import org.hibernate.jpamodelgen.MetaSingleAttribute;
import javax.lang.model.element.Element;
import org.hibernate.jpamodelgen.MetaSingleAttribute;
/**
*
* @author Max Andersen
* @author Hardy Ferentschik
* @author Emmanuel Bernard
@ -30,12 +29,11 @@ import javax.lang.model.element.Element;
public class AnnotationMetaSingleAttribute extends AnnotationMetaAttribute implements MetaSingleAttribute {
public AnnotationMetaSingleAttribute(AnnotationMetaEntity parent, Element element, String type) {
super(parent, element, type);
super( parent, element, type );
}
@Override
public String getMetaType() {
return "javax.persistence.metamodel.SingularAttribute";
}
}

View File

@ -21,6 +21,7 @@ import org.testng.annotations.Test;
import org.hibernate.jpamodelgen.test.util.CompilationTest;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAbsenceOfField;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertFieldType;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertPresenceOfField;
/**
@ -81,6 +82,7 @@ public class AccessTypeTest extends CompilationTest {
@Test
public void testMemberAccessType() throws Exception {
assertPresenceOfField( Customer.class.getName() + "_", "goodPayer", "access type overriding" );
assertFieldType( Customer.class.getName() + "_", "goodPayer", Boolean.class, "access type overriding" );
}
@Override

View File

@ -0,0 +1,51 @@
// $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.test.arraytype;
import org.testng.annotations.Test;
import org.hibernate.jpamodelgen.test.util.CompilationTest;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertFieldType;
/**
* @author Hardy Ferentschik
*/
public class ArrayTest extends CompilationTest {
/**
* METAGEN-2
*/
@Test
public void testPrimitiveArray() throws Exception {
assertFieldType( Image.class.getName() + "_", "data", byte[].class, "Wrong type for field." );
}
/**
* METAGEN-2
*/
@Test
public void testIntegerArray() throws Exception {
assertFieldType(
TemperatureSamples.class.getName() + "_", "samples", Integer[].class, "Wrong type for field."
);
}
@Override
protected String getTestPackage() {
return Image.class.getPackage().getName();
}
}

View File

@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.jpamodelgen.test.accesstype;
package org.hibernate.jpamodelgen.test.arraytype;
import javax.persistence.Entity;

View File

@ -0,0 +1,36 @@
// $Id: Image.java 17903 2009-11-04 13:22:37Z 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.test.arraytype;
import javax.persistence.Entity;
/**
* @author Hardy Feretnschik
*/
@Entity
public class TemperatureSamples {
private Integer[] samples;
public Integer[] getSamples() {
return samples;
}
public void setSamples(Integer[] samples) {
this.samples = samples;
}
}

View File

@ -17,7 +17,13 @@
*/
package org.hibernate.jpamodelgen.test.util;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.testng.Assert;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.FileAssert.fail;
@ -52,6 +58,19 @@ public class TestUtil {
Assert.assertTrue( isFieldHere( className, fieldName ), errorString );
}
public static void assertFieldType(String className, String fieldName, Class expectedType, String errorString)
throws ClassNotFoundException {
Field field = getField( className, fieldName );
assertNotNull( field );
ParameterizedType type = ( ParameterizedType ) field.getGenericType();
Type actualType = type.getActualTypeArguments()[1];
if ( expectedType.isArray() ) {
expectedType = expectedType.getComponentType();
actualType = ( ( GenericArrayType ) actualType ).getGenericComponentType();
}
assertEquals( actualType, expectedType, errorString );
}
public static void assertSuperClass(String className, String superClassName) {
Class<?> clazz;
Class<?> superClazz;
@ -69,13 +88,16 @@ public class TestUtil {
}
private static boolean isFieldHere(String className, String fieldName) throws ClassNotFoundException {
return getField( className, fieldName ) != null;
}
private static Field getField(String className, String fieldName) throws ClassNotFoundException {
Class<?> clazz = Class.forName( className );
try {
clazz.getField( fieldName );
return true;
return clazz.getField( fieldName );
}
catch ( NoSuchFieldException e ) {
return false;
return null;
}
}
}

View File

@ -4,6 +4,7 @@
<test name="Unit tests">
<packages>
<package name="org.hibernate.jpamodelgen.test.accesstype"/>
<package name="org.hibernate.jpamodelgen.test.arraytype"/>
<package name="org.hibernate.jpamodelgen.test.inheritance"/>
<package name="org.hibernate.jpamodelgen.test.xmlmapped"/>
</packages>