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,20 +17,20 @@
*/ */
package org.hibernate.jpamodelgen; package org.hibernate.jpamodelgen;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.List; import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.FilerException; import javax.annotation.processing.FilerException;
import javax.tools.FileObject; import javax.annotation.processing.ProcessingEnvironment;
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.Element;
import javax.lang.model.element.TypeElement; 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 * @author Emmanuel Bernard
@ -89,21 +89,13 @@ public class ClassWriter {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
PrintWriter pw = null; PrintWriter pw = null;
try { try {
pw = new PrintWriter( sw ); 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( Generated.class.getName() ) + "(\"JPA MetaModel for " + entity.getQualifiedName() + "\")" );
pw.println( "@" + entity.importType( "javax.persistence.metamodel.StaticMetamodel" ) + "(" + entity.getSimpleName() + ".class)" ); pw.println( "@" + entity.importType( "javax.persistence.metamodel.StaticMetamodel" ) + "(" + entity.getSimpleName() + ".class)" );
printClassDeclaration( entity, pw, context ); printClassDeclaration( entity, pw, context );
pw.println(); pw.println();
List<MetaAttribute> members = entity.getMembers(); List<MetaAttribute> members = entity.getMembers();
for ( MetaAttribute metaMember : members ) { for ( MetaAttribute metaMember : members ) {
pw.println( " " + metaMember.getDeclarationString() ); pw.println( " " + metaMember.getDeclarationString() );
} }
@ -133,7 +125,6 @@ public class ClassWriter {
pw.print( " extends " + superClassName + "_" ); pw.print( " extends " + superClassName + "_" );
} }
} }
pw.println( " {" ); pw.println( " {" );
} }
} }

View File

@ -25,38 +25,37 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name; import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement; import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement; 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.DeclaredType;
import javax.lang.model.type.ExecutableType; import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter; import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleTypeVisitor6; import javax.lang.model.util.SimpleTypeVisitor6;
import javax.persistence.EmbeddedId; import javax.persistence.Access;
import javax.persistence.Id;
import javax.persistence.AccessType; 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.Entity;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.Transient; 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 javax.tools.Diagnostic;
import org.hibernate.jpamodelgen.MetaEntity; import org.hibernate.jpamodelgen.Context;
import org.hibernate.jpamodelgen.MetaAttribute;
import org.hibernate.jpamodelgen.ImportContext; import org.hibernate.jpamodelgen.ImportContext;
import org.hibernate.jpamodelgen.ImportContextImpl; import org.hibernate.jpamodelgen.ImportContextImpl;
import org.hibernate.jpamodelgen.MetaAttribute;
import org.hibernate.jpamodelgen.MetaEntity;
import org.hibernate.jpamodelgen.TypeUtils; import org.hibernate.jpamodelgen.TypeUtils;
import org.hibernate.jpamodelgen.Context;
/** /**
*
* @author Max Andersen * @author Max Andersen
* @author Hardy Ferentschik * @author Hardy Ferentschik
* @author Emmanuel Bernard * @author Emmanuel Bernard
@ -88,10 +87,6 @@ public class AnnotationMetaEntity implements MetaEntity {
return element.getSimpleName().toString(); return element.getSimpleName().toString();
} }
public Element getOriginalElement() {
return element;
}
public String getQualifiedName() { public String getQualifiedName() {
return element.getQualifiedName().toString(); return element.getQualifiedName().toString();
} }
@ -123,11 +118,6 @@ public class AnnotationMetaEntity implements MetaEntity {
context.processElement( superclass, defaultAccessTypeForHierarchy ); 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; return membersFound;
} }
@ -136,8 +126,6 @@ public class AnnotationMetaEntity implements MetaEntity {
AccessType elementAccessType, AccessType elementAccessType,
List<? extends Element> membersOfClass, List<? extends Element> membersOfClass,
AccessType membersKind) { AccessType membersKind) {
pe.getMessager()
.printMessage( Kind.NOTE, "Scanning " + membersOfClass.size() + " " + membersKind + " for " + element.toString() );
AccessType explicitAccessType; AccessType explicitAccessType;
if ( elementAccessType == membersKind ) { if ( elementAccessType == membersKind ) {
//all membersKind considered //all membersKind considered
@ -149,16 +137,11 @@ public class AnnotationMetaEntity implements MetaEntity {
} }
for ( Element memberOfClass : membersOfClass ) { for ( Element memberOfClass : membersOfClass ) {
AnnotationMetaAttribute result = memberOfClass.asType().accept( new TypeVisitor( this, explicitAccessType ), TypeVisitor visitor = new TypeVisitor( this, explicitAccessType );
memberOfClass AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass );
);
if ( result != null ) { if ( result != null ) {
membersFound.add( result ); membersFound.add( result );
} }
//EBE not sure why?
// else {
// pe.getMessager().printMessage( Kind.WARNING, "Could not find valid info for JPA property", mymember );
// }
} }
} }
@ -216,7 +199,8 @@ public class AnnotationMetaEntity implements MetaEntity {
this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( searchedElement ); this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( searchedElement );
} }
if ( accessType != null ) { 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; return accessType;
} }
@ -227,7 +211,8 @@ public class AnnotationMetaEntity implements MetaEntity {
final Access accessAnn = searchedElement.getAnnotation( Access.class ); final Access accessAnn = searchedElement.getAnnotation( Access.class );
AccessType forcedAccessType = accessAnn != null ? accessAnn.value() : null; AccessType forcedAccessType = accessAnn != null ? accessAnn.value() : null;
if ( forcedAccessType != null ) { if ( forcedAccessType != null ) {
pe.getMessager().printMessage( Diagnostic.Kind.NOTE, "access type " + searchedElement + ":" + forcedAccessType ); pe.getMessager()
.printMessage( Diagnostic.Kind.NOTE, "access type " + searchedElement + ":" + forcedAccessType );
context.addAccessType( searchedElement, forcedAccessType ); context.addAccessType( searchedElement, forcedAccessType );
} }
@ -253,7 +238,9 @@ public class AnnotationMetaEntity implements MetaEntity {
accessType = kind == ElementKind.FIELD ? AccessType.FIELD : AccessType.PROPERTY; accessType = kind == ElementKind.FIELD ? AccessType.FIELD : AccessType.PROPERTY;
//FIXME enlever in niveau //FIXME enlever in niveau
if ( defaultAccessTypeForHierarchy == null ) { if ( defaultAccessTypeForHierarchy == null ) {
this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( searchedElement ); this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy(
searchedElement
);
//we've discovered the class hierarchy, let's cache it //we've discovered the class hierarchy, let's cache it
if ( defaultAccessTypeForHierarchy == null ) { if ( defaultAccessTypeForHierarchy == null ) {
this.defaultAccessTypeForHierarchy = accessType; this.defaultAccessTypeForHierarchy = accessType;
@ -264,7 +251,9 @@ public class AnnotationMetaEntity implements MetaEntity {
} }
if ( forcedAccessType == null ) { if ( forcedAccessType == null ) {
context.addAccessType( searchedElement, accessType ); 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; return accessType;
} }
else { else {
@ -323,6 +312,16 @@ 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) { private boolean isPersistent(Element element) {
//FIXME consider XML //FIXME consider XML
boolean correctAccessType = false; boolean correctAccessType = false;
@ -342,7 +341,6 @@ public class AnnotationMetaEntity implements MetaEntity {
} }
@Override @Override
public AnnotationMetaAttribute visitDeclared(DeclaredType t, Element element) { public AnnotationMetaAttribute visitDeclared(DeclaredType t, Element element) {
//FIXME consider XML //FIXME consider XML
@ -354,12 +352,17 @@ public class AnnotationMetaEntity implements MetaEntity {
//collection of element //collection of element
if ( element.getAnnotation( ElementCollection.class ) != null ) { if ( element.getAnnotation( ElementCollection.class ) != null ) {
final TypeMirror collectionType = t.getTypeArguments().get( 0 ); final TypeMirror collectionType = t.getTypeArguments().get( 0 );
final TypeElement collectionElement = ( TypeElement ) pe.getTypeUtils().asElement( collectionType ); final TypeElement collectionElement = ( TypeElement ) pe.getTypeUtils()
this.parent.context.processElement( collectionElement, .asElement( collectionType );
this.parent.defaultAccessTypeForElement ); this.parent.context.processElement(
collectionElement,
this.parent.defaultAccessTypeForElement
);
} }
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) { 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 { else {
return new AnnotationMetaCollection( parent, element, collection, getElementType( t ) ); return new AnnotationMetaCollection( parent, element, collection, getElementType( t ) );
@ -369,10 +372,14 @@ public class AnnotationMetaEntity implements MetaEntity {
//FIXME Consider XML //FIXME Consider XML
if ( element.getAnnotation( Embedded.class ) != null if ( element.getAnnotation( Embedded.class ) != null
|| returnedElement.getAnnotation( Embeddable.class ) != null ) { || returnedElement.getAnnotation( Embeddable.class ) != null ) {
this.parent.context.processElement( returnedElement, this.parent.context.processElement(
this.parent.defaultAccessTypeForElement ); returnedElement,
this.parent.defaultAccessTypeForElement
);
} }
return new AnnotationMetaSingleAttribute( parent, element, returnedElement.getQualifiedName().toString() ); return new AnnotationMetaSingleAttribute(
parent, element, returnedElement.getQualifiedName().toString()
);
} }
} }
else { else {
@ -380,7 +387,6 @@ public class AnnotationMetaEntity implements MetaEntity {
} }
} }
@Override @Override
public AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) { public AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) {
String string = p.getSimpleName().toString(); String string = p.getSimpleName().toString();
@ -421,7 +427,6 @@ public class AnnotationMetaEntity implements MetaEntity {
return t.getTypeArguments().get( 0 ).toString(); return t.getTypeArguments().get( 0 ).toString();
} }
private String getElementType(DeclaredType declaredType) { private String getElementType(DeclaredType declaredType) {
if ( declaredType.getTypeArguments().size() == 1 ) { if ( declaredType.getTypeArguments().size() == 1 ) {
return declaredType.getTypeArguments().get( 0 ).toString(); return declaredType.getTypeArguments().get( 0 ).toString();

View File

@ -17,12 +17,11 @@
*/ */
package org.hibernate.jpamodelgen.annotation; package org.hibernate.jpamodelgen.annotation;
import org.hibernate.jpamodelgen.MetaSingleAttribute;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import org.hibernate.jpamodelgen.MetaSingleAttribute;
/** /**
*
* @author Max Andersen * @author Max Andersen
* @author Hardy Ferentschik * @author Hardy Ferentschik
* @author Emmanuel Bernard * @author Emmanuel Bernard
@ -37,5 +36,4 @@ public class AnnotationMetaSingleAttribute extends AnnotationMetaAttribute imple
public String getMetaType() { public String getMetaType() {
return "javax.persistence.metamodel.SingularAttribute"; return "javax.persistence.metamodel.SingularAttribute";
} }
} }

View File

@ -21,6 +21,7 @@ import org.testng.annotations.Test;
import org.hibernate.jpamodelgen.test.util.CompilationTest; import org.hibernate.jpamodelgen.test.util.CompilationTest;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAbsenceOfField; 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; import static org.hibernate.jpamodelgen.test.util.TestUtil.assertPresenceOfField;
/** /**
@ -81,6 +82,7 @@ public class AccessTypeTest extends CompilationTest {
@Test @Test
public void testMemberAccessType() throws Exception { public void testMemberAccessType() throws Exception {
assertPresenceOfField( Customer.class.getName() + "_", "goodPayer", "access type overriding" ); assertPresenceOfField( Customer.class.getName() + "_", "goodPayer", "access type overriding" );
assertFieldType( Customer.class.getName() + "_", "goodPayer", Boolean.class, "access type overriding" );
} }
@Override @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 * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.hibernate.jpamodelgen.test.accesstype; package org.hibernate.jpamodelgen.test.arraytype;
import javax.persistence.Entity; 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; 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 org.testng.Assert;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import static org.testng.FileAssert.fail; import static org.testng.FileAssert.fail;
@ -52,6 +58,19 @@ public class TestUtil {
Assert.assertTrue( isFieldHere( className, fieldName ), errorString ); 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) { public static void assertSuperClass(String className, String superClassName) {
Class<?> clazz; Class<?> clazz;
Class<?> superClazz; Class<?> superClazz;
@ -69,13 +88,16 @@ public class TestUtil {
} }
private static boolean isFieldHere(String className, String fieldName) throws ClassNotFoundException { 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 ); Class<?> clazz = Class.forName( className );
try { try {
clazz.getField( fieldName ); return clazz.getField( fieldName );
return true;
} }
catch ( NoSuchFieldException e ) { catch ( NoSuchFieldException e ) {
return false; return null;
} }
} }
} }

View File

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