METAGEN-30

This commit is contained in:
Hardy Ferentschik 2010-09-27 17:28:10 +00:00 committed by Strong Liu
parent 6098243f7a
commit 489c46b4be
13 changed files with 273 additions and 65 deletions

View File

@ -41,6 +41,9 @@ import org.hibernate.jpamodelgen.model.MetaEntity;
*/
public class ClassWriter {
private ClassWriter(){
}
public static void writeFile(MetaEntity entity, Context context) {
try {
String metaModelPackage = entity.getPackageName();

View File

@ -34,11 +34,11 @@ import org.hibernate.jpamodelgen.model.ImportContext;
*/
public class ImportContextImpl implements ImportContext {
Set<String> imports = new TreeSet<String>();
Set<String> staticImports = new TreeSet<String>();
Map<String, String> simpleNames = new HashMap<String, String>();
private Set<String> imports = new TreeSet<String>();
private Set<String> staticImports = new TreeSet<String>();
private Map<String, String> simpleNames = new HashMap<String, String>();
String basePackage = "";
private String basePackage = "";
private static final Map<String, String> PRIMITIVES = new HashMap<String, String>();
@ -161,15 +161,13 @@ public class ImportContextImpl implements ImportContext {
StringBuffer buf = new StringBuffer();
for ( String next : imports ) {
if ( isPrimitive( next ) || inDefaultPackage( next ) || inJavaLang( next ) || inSamePackage( next ) ) {
// dont add automatically "imported" stuff
}
else {
// don't add automatically "imported" stuff
if ( !isAutoImported( next ) ) {
if ( staticImports.contains( next ) ) {
buf.append( "import static " + next + ";\r\n" );
buf.append( "import static " ).append( next ).append( ";\r\n" );
}
else {
buf.append( "import " + next + ";\r\n" );
buf.append( "import " ).append( next ).append( ";\r\n" );
}
}
}
@ -180,9 +178,13 @@ public class ImportContextImpl implements ImportContext {
return buf.toString();
}
private boolean isAutoImported(String next) {
return isPrimitive( next ) || inDefaultPackage( next ) || inJavaLang( next ) || inSamePackage( next );
}
public static String unqualify(String qualifiedName) {
int loc = qualifiedName.lastIndexOf( "." );
return ( loc < 0 ) ? qualifiedName : qualifiedName.substring( qualifiedName.lastIndexOf( "." ) + 1 );
int loc = qualifiedName.lastIndexOf( '.' );
return ( loc < 0 ) ? qualifiedName : qualifiedName.substring( qualifiedName.lastIndexOf( '.' ) + 1 );
}
public static String qualifier(String qualifiedName) {

View File

@ -25,16 +25,19 @@ import javax.lang.model.element.ElementKind;
import javax.lang.model.util.Elements;
import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.MetaEntity;
/**
* Captures all information about an annotated persistent attribute.
*
* @author Max Andersen
* @author Hardy Ferentschik
* @author Emmanuel Bernard
*/
public abstract class AnnotationMetaAttribute implements MetaAttribute {
final protected Element element;
final protected AnnotationMetaEntity parent;
private final Element element;
private final AnnotationMetaEntity parent;
private final String type;
public AnnotationMetaAttribute(AnnotationMetaEntity parent, Element element, String type) {
@ -44,8 +47,16 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
}
public String getDeclarationString() {
return "public static volatile " + parent.importType( getMetaType() ) + "<" + parent.importType( parent.getQualifiedName() ) + ", " + parent
.importType( getTypeDeclaration() ) + "> " + getPropertyName() + ";";
return new StringBuilder().append( "public static volatile " )
.append( parent.importType( getMetaType() ) )
.append( "<" )
.append( parent.importType( parent.getQualifiedName() ) )
.append( ", " )
.append( parent.importType( getTypeDeclaration() ) )
.append( "> " )
.append( getPropertyName() )
.append( ";" )
.toString();
}
public String getPropertyName() {
@ -68,6 +79,10 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
}
}
public MetaEntity getParent() {
return parent;
}
abstract public String getMetaType();
public String getTypeDeclaration() {

View File

@ -63,6 +63,8 @@ import org.hibernate.jpamodelgen.util.StringUtil;
import org.hibernate.jpamodelgen.util.TypeUtils;
/**
* Class used to collect meta information about an annotated entity.
*
* @author Max Andersen
* @author Hardy Ferentschik
* @author Emmanuel Bernard
@ -185,6 +187,13 @@ public class AnnotationMetaEntity implements MetaEntity {
}
class TypeVisitor extends SimpleTypeVisitor6<AnnotationMetaAttribute, Element> {
/**
* FQCN of the Hibernate specific @Target annotation. We do not use the class directly to avoid depending on Hibernate
* Core.
*/
private static final String ORG_HIBERNATE_ANNOTATIONS_TARGET = "org.hibernate.annotations.Target";
AnnotationMetaEntity parent;
TypeVisitor(AnnotationMetaEntity parent) {
@ -229,55 +238,57 @@ public class AnnotationMetaEntity implements MetaEntity {
@Override
public AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) {
AnnotationMetaAttribute metaAttribute = null;
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 = 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 = TypeUtils.getCollectionElementType(
declaredType, fqNameOfReturnType, explicitTargetEntity, context
return createMetaCollectionAttribute(
declaredType, element, fqNameOfReturnType, collection, targetEntity
);
}
else if ( isBasicAttribute( element, returnedElement ) ) {
String type = targetEntity != null ? targetEntity : returnedElement.getQualifiedName().toString();
return new AnnotationMetaSingleAttribute( parent, element, type );
}
return metaAttribute;
}
private AnnotationMetaAttribute createMetaCollectionAttribute(DeclaredType declaredType, Element element, String fqNameOfReturnType, String collection, String targetEntity) {
if ( TypeUtils.containsAnnotation( element, ElementCollection.class ) ) {
String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() );
TypeMirror collectionElementType = TypeUtils.getCollectionElementType(
declaredType, fqNameOfReturnType, explicitTargetEntity, context
);
final TypeElement collectionElement = ( TypeElement ) context.getTypeUtils()
.asElement( collectionElementType );
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( collectionElement.getQualifiedName().toString() );
if ( accessTypeInfo == null ) {
AccessType explicitAccessType = TypeUtils.determineAnnotationSpecifiedAccessType(
collectionElement
);
accessTypeInfo = new AccessTypeInformation(
collectionElement.getQualifiedName().toString(),
explicitAccessType,
entityAccessTypeInfo.getAccessType()
);
context.addAccessTypeInformation(
collectionElement.getQualifiedName().toString(), accessTypeInfo
);
final TypeElement collectionElement = ( TypeElement ) context.getTypeUtils()
.asElement( collectionElementType );
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( collectionElement.getQualifiedName().toString() );
if ( accessTypeInfo == null ) {
AccessType explicitAccessType = TypeUtils.determineAnnotationSpecifiedAccessType(
collectionElement
);
accessTypeInfo = new AccessTypeInformation(
collectionElement.getQualifiedName().toString(),
explicitAccessType,
entityAccessTypeInfo.getAccessType()
);
context.addAccessTypeInformation(
collectionElement.getQualifiedName().toString(), accessTypeInfo
);
}
else {
accessTypeInfo.setDefaultAccessType( entityAccessTypeInfo.getAccessType() );
}
}
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity );
}
else {
return new AnnotationMetaCollection(
parent, element, collection, getElementType( declaredType, targetEntity )
);
accessTypeInfo.setDefaultAccessType( entityAccessTypeInfo.getAccessType() );
}
}
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity );
}
else {
if ( isBasicAttribute( element, returnedElement ) ) {
return new AnnotationMetaSingleAttribute(
parent, element, returnedElement.getQualifiedName().toString()
);
}
else {
return null;
}
return new AnnotationMetaCollection(
parent, element, collection, getElementType( declaredType, targetEntity )
);
}
}
@ -359,7 +370,6 @@ public class AnnotationMetaEntity implements MetaEntity {
* @return target entity class name as string or {@code null} if no targetEntity is here or if equals to void
*/
private String getTargetEntity(List<? extends AnnotationMirror> annotations) {
String fullyQualifiedTargetEntityName = null;
for ( AnnotationMirror mirror : annotations ) {
if ( TypeUtils.isAnnotationMirrorOfType( mirror, ElementCollection.class ) ) {
@ -371,6 +381,9 @@ public class AnnotationMetaEntity implements MetaEntity {
|| TypeUtils.isAnnotationMirrorOfType( mirror, OneToOne.class ) ) {
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetEntity" );
}
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, ORG_HIBERNATE_ANNOTATIONS_TARGET ) ) {
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "value" );
}
}
return fullyQualifiedTargetEntityName;
}
@ -415,7 +428,7 @@ public class AnnotationMetaEntity implements MetaEntity {
return Boolean.TRUE;
}
if ( ElementKind.CLASS.equals( element.getKind() ) || ElementKind.INTERFACE.equals( element.getKind() )) {
if ( ElementKind.CLASS.equals( element.getKind() ) || ElementKind.INTERFACE.equals( element.getKind() ) ) {
TypeElement typeElement = ( ( TypeElement ) element );
String typeName = typeElement.getQualifiedName().toString();
if ( Constants.BASIC_TYPES.contains( typeName ) ) {

View File

@ -37,7 +37,7 @@ public class AnnotationMetaMap extends AnnotationMetaCollection {
}
public String getDeclarationString() {
return "public static volatile " + parent.importType( getMetaType() ) + "<" + parent.importType( parent.getQualifiedName() ) + ", " + parent
.importType( keyType ) + ", " + parent.importType( getTypeDeclaration() ) + "> " + getPropertyName() + ";";
return "public static volatile " + getParent().importType( getMetaType() ) + "<" + getParent().importType( getParent().getQualifiedName() ) + ", " + getParent()
.importType( keyType ) + ", " + getParent().importType( getTypeDeclaration() ) + "> " + getPropertyName() + ";";
}
}

View File

@ -35,7 +35,7 @@ public class AnnotationMetaSingleAttribute extends AnnotationMetaAttribute imple
}
@Override
public String getMetaType() {
public final String getMetaType() {
return "javax.persistence.metamodel.SingularAttribute";
}
}

View File

@ -30,4 +30,6 @@ public interface MetaAttribute {
String getPropertyName();
String getTypeDeclaration();
MetaEntity getParent();
}

View File

@ -79,14 +79,17 @@ public class TypeUtils {
}
static public String toTypeString(TypeMirror type) {
private TypeUtils() {
}
public static String toTypeString(TypeMirror type) {
if ( type.getKind().isPrimitive() ) {
return PRIMITIVES.get( type.toString() );
}
return type.toString();
}
static public TypeElement getSuperclassTypeElement(TypeElement element) {
public static TypeElement getSuperclassTypeElement(TypeElement element) {
final TypeMirror superClass = element.getSuperclass();
//superclass of Object is of NoType which returns some other kind
if ( superClass.getKind() == TypeKind.DECLARED ) {
@ -140,17 +143,30 @@ public class TypeUtils {
* This method uses the string class names for comparison. See also {@link http://www.retep.org/2009/02/getting-class-values-from-annotations.html}.
*
* @param annotationMirror The annotation mirror
* @param clazz the class name to check again
* @param clazz the class name to check against
*
* @return {@code true} if the provided annotation type is of the same type as the provided class, {@code false} otherwise.
*/
public static boolean isAnnotationMirrorOfType(AnnotationMirror annotationMirror, Class<? extends Annotation> clazz) {
assert annotationMirror != null;
assert clazz != null;
String annotationClassName = annotationMirror.getAnnotationType().toString();
String className = clazz.getName();
return isAnnotationMirrorOfType( annotationMirror, clazz.getName() );
}
return annotationClassName.equals( className );
/**
* Returns {@code true} if the provided annotation type is of the same type as the provided class, {@code false} otherwise.
* This method uses the string class names for comparison. See also {@link http://www.retep.org/2009/02/getting-class-values-from-annotations.html}.
*
* @param annotationMirror The annotation mirror
* @param fqcn the fully qualified class name to check against
*
* @return {@code true} if the provided annotation type is of the same type as the provided class, {@code false} otherwise.
*/
public static boolean isAnnotationMirrorOfType(AnnotationMirror annotationMirror, String fqcn) {
assert annotationMirror != null;
assert fqcn != null;
String annotationClassName = annotationMirror.getAnnotationType().toString();
return annotationClassName.equals( fqcn );
}
public static boolean isTypeElementOfType(TypeElement element, Class<?> clazz) {

View File

@ -21,6 +21,7 @@
package org.hibernate.jpamodelgen.xml;
import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.MetaEntity;
/**
* @author Hardy Ferentschik
@ -53,6 +54,10 @@ public abstract class XmlMetaAttribute implements MetaAttribute {
return type;
}
public MetaEntity getParent() {
return parentEntity;
}
@Override
abstract public String getMetaType();

View File

@ -0,0 +1,30 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// $Id:$
package org.hibernate.jpamodelgen.test.targetannotation;
import javax.persistence.Embeddable;
/**
* @author Hardy Ferentschik
*/
@Embeddable
public interface Address {
}

View File

@ -0,0 +1,27 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// $Id:$
package org.hibernate.jpamodelgen.test.targetannotation;
/**
* @author Hardy Ferentschik
*/
public class AddressImpl implements Address {
}

View File

@ -0,0 +1,47 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// $Id:$
package org.hibernate.jpamodelgen.test.targetannotation;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Target;
/**
* @author Hardy Ferentschik
*/
@Entity
class House {
@Id
long id;
@Embedded
@Target(AddressImpl.class)
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}

View File

@ -0,0 +1,48 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// $Id$
package org.hibernate.jpamodelgen.test.targetannotation;
import org.testng.annotations.Test;
import org.hibernate.jpamodelgen.test.util.CompilationTest;
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;
/**
* @author Hardy Ferentschik
*/
public class TargetAnnotationTest extends CompilationTest {
/**
* METAGEN-30
*/
@Test
public void testEmbeddableWithTargetAnnotation() {
assertMetamodelClassGeneratedFor( House.class );
assertPresenceOfFieldInMetamodelFor( House.class, "address", "the metamodel should have a member 'address'" );
assertAttributeTypeInMetaModelFor( House.class, "address", AddressImpl.class, "The target annotation set the type to AddressImpl");
}
@Override
protected String getPackageNameOfTestSources() {
return TargetAnnotationTest.class.getPackage().getName();
}
}