METAGEN-37 fixed TypeUtils.extractClosestRealTypeAsString and added test
This commit is contained in:
parent
9dcc29c6ef
commit
1720d85543
|
@ -24,7 +24,10 @@ package org.hibernate.jpamodelgen;
|
||||||
*
|
*
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
*/
|
*/
|
||||||
public class Version {
|
public final class Version {
|
||||||
|
private Version() {
|
||||||
|
}
|
||||||
|
|
||||||
public static String getVersionString() {
|
public static String getVersionString() {
|
||||||
return "[WORKING]";
|
return "[WORKING]";
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,33 +24,14 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
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.Modifier;
|
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.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.TypeKind;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
import javax.lang.model.type.TypeVariable;
|
|
||||||
import javax.lang.model.util.ElementFilter;
|
import javax.lang.model.util.ElementFilter;
|
||||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
|
||||||
import javax.persistence.AccessType;
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Basic;
|
|
||||||
import javax.persistence.ElementCollection;
|
|
||||||
import javax.persistence.Embeddable;
|
|
||||||
import javax.persistence.ManyToMany;
|
|
||||||
import javax.persistence.ManyToOne;
|
|
||||||
import javax.persistence.MapKeyClass;
|
|
||||||
import javax.persistence.OneToMany;
|
|
||||||
import javax.persistence.OneToOne;
|
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
import javax.tools.Diagnostic;
|
|
||||||
|
|
||||||
import org.hibernate.jpamodelgen.AccessTypeInformation;
|
import org.hibernate.jpamodelgen.AccessTypeInformation;
|
||||||
import org.hibernate.jpamodelgen.Context;
|
import org.hibernate.jpamodelgen.Context;
|
||||||
|
@ -58,8 +39,6 @@ import org.hibernate.jpamodelgen.ImportContextImpl;
|
||||||
import org.hibernate.jpamodelgen.model.ImportContext;
|
import org.hibernate.jpamodelgen.model.ImportContext;
|
||||||
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
||||||
import org.hibernate.jpamodelgen.model.MetaEntity;
|
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.util.TypeUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,6 +71,10 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AccessTypeInformation getEntityAccessTypeInfo() {
|
||||||
|
return entityAccessTypeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
public Context getContext() {
|
public Context getContext() {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +116,7 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
sb.append( '}' );
|
sb.append( '}' );
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) {
|
private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) {
|
||||||
for ( Element memberOfClass : membersOfClass ) {
|
for ( Element memberOfClass : membersOfClass ) {
|
||||||
AccessType forcedAccessType = TypeUtils.determineAnnotationSpecifiedAccessType( memberOfClass );
|
AccessType forcedAccessType = TypeUtils.determineAnnotationSpecifiedAccessType( memberOfClass );
|
||||||
|
@ -147,7 +130,7 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeVisitor visitor = new TypeVisitor( this );
|
MetaAttributeGenerationVisitor visitor = new MetaAttributeGenerationVisitor( this, context );
|
||||||
AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass );
|
AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass );
|
||||||
if ( result != null ) {
|
if ( result != null ) {
|
||||||
members.put( result.getPropertyName(), result );
|
members.put( result.getPropertyName(), result );
|
||||||
|
@ -155,7 +138,7 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init() {
|
protected final void init() {
|
||||||
TypeUtils.determineAccessTypeForHierarchy( element, context );
|
TypeUtils.determineAccessTypeForHierarchy( element, context );
|
||||||
entityAccessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
entityAccessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
||||||
|
|
||||||
|
@ -166,285 +149,23 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
addPersistentMembers( methodsOfClass, AccessType.PROPERTY );
|
addPersistentMembers( methodsOfClass, AccessType.PROPERTY );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateImports() {
|
public final String generateImports() {
|
||||||
return importContext.generateImports();
|
return importContext.generateImports();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String importType(String fqcn) {
|
public final String importType(String fqcn) {
|
||||||
return importContext.importType( fqcn );
|
return importContext.importType( fqcn );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String staticImport(String fqcn, String member) {
|
public final String staticImport(String fqcn, String member) {
|
||||||
return importContext.staticImport( fqcn, member );
|
return importContext.staticImport( fqcn, member );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String importType(Name qualifiedName) {
|
public final String importType(Name qualifiedName) {
|
||||||
return importType( qualifiedName.toString() );
|
return importType( qualifiedName.toString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeElement getTypeElement() {
|
public final TypeElement getTypeElement() {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) {
|
|
||||||
return new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnnotationMetaAttribute visitArray(ArrayType t, Element element) {
|
|
||||||
// METAGEN-2 - For now we handle arrays as SingularAttribute
|
|
||||||
// The code below is an attempt to be closer to the spec and only allow byte[], Byte[], char[] and Character[]
|
|
||||||
// AnnotationMetaSingleAttribute attribute = null;
|
|
||||||
// TypeMirror componentMirror = t.getComponentType();
|
|
||||||
// if ( TypeKind.CHAR.equals( componentMirror.getKind() )
|
|
||||||
// || TypeKind.BYTE.equals( componentMirror.getKind() ) ) {
|
|
||||||
// attribute = new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) );
|
|
||||||
// }
|
|
||||||
// else if ( TypeKind.DECLARED.equals( componentMirror.getKind() ) ) {
|
|
||||||
// TypeElement componentElement = ( TypeElement ) context.getProcessingEnvironment()
|
|
||||||
// .getTypeUtils()
|
|
||||||
// .asElement( componentMirror );
|
|
||||||
// if ( BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() ) ) {
|
|
||||||
// attribute = new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return attribute;
|
|
||||||
return new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnnotationMetaAttribute visitTypeVariable(TypeVariable t, Element element) {
|
|
||||||
// METAGEN-29 - for a type variable we use the upper bound
|
|
||||||
TypeMirror mirror = t.getUpperBound();
|
|
||||||
TypeMirror erasedType = context.getTypeUtils().erasure( mirror );
|
|
||||||
return new AnnotationMetaSingleAttribute(
|
|
||||||
parent, element, erasedType.toString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 ) {
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
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 )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnnotationMetaAttribute 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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isBasicAttribute(Element element, Element returnedElement) {
|
|
||||||
if ( TypeUtils.containsAnnotation( element, Basic.class )
|
|
||||||
|| TypeUtils.containsAnnotation( element, OneToOne.class )
|
|
||||||
|| TypeUtils.containsAnnotation( element, ManyToOne.class ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicAttributeVisitor basicVisitor = new BasicAttributeVisitor();
|
|
||||||
return returnedElement.asType().accept( basicVisitor, returnedElement );
|
|
||||||
}
|
|
||||||
|
|
||||||
private AnnotationMetaAttribute createAnnotationMetaAttributeForMap(DeclaredType declaredType, Element element, String collection, String targetEntity) {
|
|
||||||
String keyType;
|
|
||||||
if ( TypeUtils.containsAnnotation( element, MapKeyClass.class ) ) {
|
|
||||||
TypeMirror typeMirror = ( TypeMirror ) TypeUtils.getAnnotationValue(
|
|
||||||
TypeUtils.getAnnotationMirror(
|
|
||||||
element, MapKeyClass.class
|
|
||||||
), TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME
|
|
||||||
);
|
|
||||||
keyType = typeMirror.toString();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
keyType = TypeUtils.getKeyType( declaredType, context );
|
|
||||||
}
|
|
||||||
return new AnnotationMetaMap(
|
|
||||||
parent,
|
|
||||||
element,
|
|
||||||
collection,
|
|
||||||
keyType,
|
|
||||||
getElementType( declaredType, targetEntity )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getElementType(DeclaredType declaredType, String targetEntity) {
|
|
||||||
if ( targetEntity != null ) {
|
|
||||||
return targetEntity;
|
|
||||||
}
|
|
||||||
final List<? extends TypeMirror> mirrors = declaredType.getTypeArguments();
|
|
||||||
if ( mirrors.size() == 1 ) {
|
|
||||||
final TypeMirror type = mirrors.get( 0 );
|
|
||||||
return TypeUtils.extractClosestRealTypeAsString( type, context );
|
|
||||||
}
|
|
||||||
else if ( mirrors.size() == 2 ) {
|
|
||||||
return TypeUtils.extractClosestRealTypeAsString( mirrors.get( 1 ), context );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//for 0 or many
|
|
||||||
//0 is expected, many is not
|
|
||||||
if ( mirrors.size() > 2 ) {
|
|
||||||
context.logMessage(
|
|
||||||
Diagnostic.Kind.WARNING, "Unable to find the closest solid type" + declaredType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param annotations list of annotation mirrors.
|
|
||||||
*
|
|
||||||
* @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 ) ) {
|
|
||||||
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetClass" );
|
|
||||||
}
|
|
||||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, OneToMany.class )
|
|
||||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, ManyToMany.class )
|
|
||||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, ManyToOne.class )
|
|
||||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, OneToOne.class ) ) {
|
|
||||||
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetEntity" );
|
|
||||||
}
|
|
||||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, ORG_HIBERNATE_ANNOTATIONS_TARGET ) ) {
|
|
||||||
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "value" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fullyQualifiedTargetEntityName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getFullyQualifiedClassNameOfTargetEntity(AnnotationMirror mirror, String parameterName) {
|
|
||||||
assert mirror != null;
|
|
||||||
assert parameterName != null;
|
|
||||||
|
|
||||||
String targetEntityName = null;
|
|
||||||
Object parameterValue = TypeUtils.getAnnotationValue( mirror, parameterName );
|
|
||||||
if ( parameterValue != null ) {
|
|
||||||
TypeMirror parameterType = ( TypeMirror ) parameterValue;
|
|
||||||
if ( !parameterType.getKind().equals( TypeKind.VOID ) ) {
|
|
||||||
targetEntityName = parameterType.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return targetEntityName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
public Boolean visitPrimitive(PrimitiveType t, Element element) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitArray(ArrayType t, Element element) {
|
|
||||||
TypeMirror componentMirror = t.getComponentType();
|
|
||||||
TypeElement componentElement = ( TypeElement ) context.getTypeUtils().asElement( componentMirror );
|
|
||||||
|
|
||||||
return Constants.BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitDeclared(DeclaredType declaredType, Element element) {
|
|
||||||
if ( ElementKind.ENUM.equals( element.getKind() ) ) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ) ) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
if ( TypeUtils.containsAnnotation( element, Embeddable.class ) ) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
for ( TypeMirror mirror : typeElement.getInterfaces() ) {
|
|
||||||
TypeElement interfaceElement = ( TypeElement ) context.getTypeUtils().asElement( mirror );
|
|
||||||
if ( "java.io.Serializable".equals( interfaceElement.getQualifiedName().toString() ) ) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Boolean.FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
/*
|
||||||
|
* 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.annotation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
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.TypeKind;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.type.TypeVariable;
|
||||||
|
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
|
import javax.persistence.Basic;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.MapKeyClass;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
|
||||||
|
import org.hibernate.jpamodelgen.AccessTypeInformation;
|
||||||
|
import org.hibernate.jpamodelgen.Context;
|
||||||
|
import org.hibernate.jpamodelgen.util.Constants;
|
||||||
|
import org.hibernate.jpamodelgen.util.StringUtil;
|
||||||
|
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
*/
|
||||||
|
public class MetaAttributeGenerationVisitor 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";
|
||||||
|
|
||||||
|
private final AnnotationMetaEntity entity;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
MetaAttributeGenerationVisitor(AnnotationMetaEntity entity, Context context) {
|
||||||
|
this.entity = entity;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) {
|
||||||
|
return new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationMetaAttribute visitArray(ArrayType t, Element element) {
|
||||||
|
// METAGEN-2 - For now we handle arrays as SingularAttribute
|
||||||
|
// The code below is an attempt to be closer to the spec and only allow byte[], Byte[], char[] and Character[]
|
||||||
|
// AnnotationMetaSingleAttribute attribute = null;
|
||||||
|
// TypeMirror componentMirror = t.getComponentType();
|
||||||
|
// if ( TypeKind.CHAR.equals( componentMirror.getKind() )
|
||||||
|
// || TypeKind.BYTE.equals( componentMirror.getKind() ) ) {
|
||||||
|
// attribute = new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
||||||
|
// }
|
||||||
|
// else if ( TypeKind.DECLARED.equals( componentMirror.getKind() ) ) {
|
||||||
|
// TypeElement componentElement = ( TypeElement ) context.getProcessingEnvironment()
|
||||||
|
// .getTypeUtils()
|
||||||
|
// .asElement( componentMirror );
|
||||||
|
// if ( BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() ) ) {
|
||||||
|
// attribute = new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return attribute;
|
||||||
|
return new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotationMetaAttribute visitTypeVariable(TypeVariable t, Element element) {
|
||||||
|
// METAGEN-29 - for a type variable we use the upper bound
|
||||||
|
TypeMirror mirror = t.getUpperBound();
|
||||||
|
TypeMirror erasedType = context.getTypeUtils().erasure( mirror );
|
||||||
|
return new AnnotationMetaSingleAttribute(
|
||||||
|
entity, element, erasedType.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 ) {
|
||||||
|
return createMetaCollectionAttribute(
|
||||||
|
declaredType, element, fqNameOfReturnType, collection, targetEntity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if ( isBasicAttribute( element, returnedElement ) ) {
|
||||||
|
String type = targetEntity != null ? targetEntity : returnedElement.getQualifiedName().toString();
|
||||||
|
return new AnnotationMetaSingleAttribute( entity, 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,
|
||||||
|
entity.getEntityAccessTypeInfo().getAccessType()
|
||||||
|
);
|
||||||
|
context.addAccessTypeInformation(
|
||||||
|
collectionElement.getQualifiedName().toString(), accessTypeInfo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
accessTypeInfo.setDefaultAccessType( entity.getEntityAccessTypeInfo().getAccessType() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
|
||||||
|
return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new AnnotationMetaCollection(
|
||||||
|
entity, element, collection, getElementType( declaredType, targetEntity )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnnotationMetaAttribute 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBasicAttribute(Element element, Element returnedElement) {
|
||||||
|
if ( TypeUtils.containsAnnotation( element, Basic.class )
|
||||||
|
|| TypeUtils.containsAnnotation( element, OneToOne.class )
|
||||||
|
|| TypeUtils.containsAnnotation( element, ManyToOne.class ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicAttributeVisitor basicVisitor = new BasicAttributeVisitor( context );
|
||||||
|
return returnedElement.asType().accept( basicVisitor, returnedElement );
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnnotationMetaAttribute createAnnotationMetaAttributeForMap(DeclaredType declaredType, Element element, String collection, String targetEntity) {
|
||||||
|
String keyType;
|
||||||
|
if ( TypeUtils.containsAnnotation( element, MapKeyClass.class ) ) {
|
||||||
|
TypeMirror typeMirror = (TypeMirror) TypeUtils.getAnnotationValue(
|
||||||
|
TypeUtils.getAnnotationMirror(
|
||||||
|
element, MapKeyClass.class
|
||||||
|
), TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME
|
||||||
|
);
|
||||||
|
keyType = typeMirror.toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
keyType = TypeUtils.getKeyType( declaredType, context );
|
||||||
|
}
|
||||||
|
return new AnnotationMetaMap(
|
||||||
|
entity,
|
||||||
|
element,
|
||||||
|
collection,
|
||||||
|
keyType,
|
||||||
|
getElementType( declaredType, targetEntity )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getElementType(DeclaredType declaredType, String targetEntity) {
|
||||||
|
if ( targetEntity != null ) {
|
||||||
|
return targetEntity;
|
||||||
|
}
|
||||||
|
final List<? extends TypeMirror> mirrors = declaredType.getTypeArguments();
|
||||||
|
if ( mirrors.size() == 1 ) {
|
||||||
|
final TypeMirror type = mirrors.get( 0 );
|
||||||
|
return TypeUtils.extractClosestRealTypeAsString( type, context );
|
||||||
|
}
|
||||||
|
else if ( mirrors.size() == 2 ) {
|
||||||
|
return TypeUtils.extractClosestRealTypeAsString( mirrors.get( 1 ), context );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//for 0 or many
|
||||||
|
//0 is expected, many is not
|
||||||
|
if ( mirrors.size() > 2 ) {
|
||||||
|
context.logMessage(
|
||||||
|
Diagnostic.Kind.WARNING, "Unable to find the closest solid type" + declaredType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param annotations list of annotation mirrors.
|
||||||
|
*
|
||||||
|
* @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 ) ) {
|
||||||
|
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetClass" );
|
||||||
|
}
|
||||||
|
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, OneToMany.class )
|
||||||
|
|| TypeUtils.isAnnotationMirrorOfType( mirror, ManyToMany.class )
|
||||||
|
|| TypeUtils.isAnnotationMirrorOfType( mirror, ManyToOne.class )
|
||||||
|
|| TypeUtils.isAnnotationMirrorOfType( mirror, OneToOne.class ) ) {
|
||||||
|
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetEntity" );
|
||||||
|
}
|
||||||
|
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, ORG_HIBERNATE_ANNOTATIONS_TARGET ) ) {
|
||||||
|
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "value" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fullyQualifiedTargetEntityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFullyQualifiedClassNameOfTargetEntity(AnnotationMirror mirror, String parameterName) {
|
||||||
|
assert mirror != null;
|
||||||
|
assert parameterName != null;
|
||||||
|
|
||||||
|
String targetEntityName = null;
|
||||||
|
Object parameterValue = TypeUtils.getAnnotationValue( mirror, parameterName );
|
||||||
|
if ( parameterValue != null ) {
|
||||||
|
TypeMirror parameterType = (TypeMirror) parameterValue;
|
||||||
|
if ( !parameterType.getKind().equals( TypeKind.VOID ) ) {
|
||||||
|
targetEntityName = parameterType.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targetEntityName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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> {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public BasicAttributeVisitor(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visitPrimitive(PrimitiveType t, Element element) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visitArray(ArrayType t, Element element) {
|
||||||
|
TypeMirror componentMirror = t.getComponentType();
|
||||||
|
TypeElement componentElement = (TypeElement) context.getTypeUtils().asElement( componentMirror );
|
||||||
|
|
||||||
|
return Constants.BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visitDeclared(DeclaredType declaredType, Element element) {
|
||||||
|
if ( ElementKind.ENUM.equals( element.getKind() ) ) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ) ) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
if ( TypeUtils.containsAnnotation( element, Embeddable.class ) ) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
for ( TypeMirror mirror : typeElement.getInterfaces() ) {
|
||||||
|
TypeElement interfaceElement = (TypeElement) context.getTypeUtils().asElement( mirror );
|
||||||
|
if ( "java.io.Serializable".equals( interfaceElement.getQualifiedName().toString() ) ) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@ import javax.lang.model.type.TypeVariable;
|
||||||
import javax.lang.model.util.ElementFilter;
|
import javax.lang.model.util.ElementFilter;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||||
import javax.lang.model.util.Types;
|
|
||||||
import javax.persistence.Access;
|
import javax.persistence.Access;
|
||||||
import javax.persistence.AccessType;
|
import javax.persistence.AccessType;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
|
@ -59,7 +58,7 @@ import org.hibernate.jpamodelgen.MetaModelGenerationException;
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
*/
|
*/
|
||||||
public class TypeUtils {
|
public final class TypeUtils {
|
||||||
|
|
||||||
public static final String DEFAULT_ANNOTATION_PARAMETER_NAME = "value";
|
public static final String DEFAULT_ANNOTATION_PARAMETER_NAME = "value";
|
||||||
private static final Map<String, String> PRIMITIVES = new HashMap<String, String>();
|
private static final Map<String, String> PRIMITIVES = new HashMap<String, String>();
|
||||||
|
@ -94,8 +93,8 @@ public class TypeUtils {
|
||||||
//superclass of Object is of NoType which returns some other kind
|
//superclass of Object is of NoType which returns some other kind
|
||||||
if ( superClass.getKind() == TypeKind.DECLARED ) {
|
if ( superClass.getKind() == TypeKind.DECLARED ) {
|
||||||
//F..king Ch...t Have those people used their horrible APIs even once?
|
//F..king Ch...t Have those people used their horrible APIs even once?
|
||||||
final Element superClassElement = ( ( DeclaredType ) superClass ).asElement();
|
final Element superClassElement = ( (DeclaredType) superClass ).asElement();
|
||||||
return ( TypeElement ) superClassElement;
|
return (TypeElement) superClassElement;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -104,19 +103,11 @@ public class TypeUtils {
|
||||||
|
|
||||||
public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
|
public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
|
||||||
if ( type instanceof TypeVariable ) {
|
if ( type instanceof TypeVariable ) {
|
||||||
final TypeMirror compositeUpperBound = ( ( TypeVariable ) type ).getUpperBound();
|
final TypeMirror compositeUpperBound = ( (TypeVariable) type ).getUpperBound();
|
||||||
final Types types = context.getTypeUtils();
|
return extractClosestRealTypeAsString( compositeUpperBound, context );
|
||||||
final List<? extends TypeMirror> upperBounds = types.directSupertypes( compositeUpperBound );
|
|
||||||
if ( upperBounds.size() == 0 ) {
|
|
||||||
return compositeUpperBound.toString();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//take the first one
|
|
||||||
return extractClosestRealTypeAsString( upperBounds.get( 0 ), context );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return type.toString();
|
return context.getTypeUtils().erasure( type ).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +336,7 @@ public class TypeUtils {
|
||||||
List<? extends AnnotationMirror> entityAnnotations =
|
List<? extends AnnotationMirror> entityAnnotations =
|
||||||
context.getElementUtils().getAllAnnotationMirrors( subElement );
|
context.getElementUtils().getAllAnnotationMirrors( subElement );
|
||||||
for ( Object entityAnnotation : entityAnnotations ) {
|
for ( Object entityAnnotation : entityAnnotations ) {
|
||||||
AnnotationMirror annotationMirror = ( AnnotationMirror ) entityAnnotation;
|
AnnotationMirror annotationMirror = (AnnotationMirror) entityAnnotation;
|
||||||
if ( isIdAnnotation( annotationMirror ) ) {
|
if ( isIdAnnotation( annotationMirror ) ) {
|
||||||
defaultAccessType = getAccessTypeOfIdAnnotation( subElement );
|
defaultAccessType = getAccessTypeOfIdAnnotation( subElement );
|
||||||
break;
|
break;
|
||||||
|
@ -373,7 +364,7 @@ public class TypeUtils {
|
||||||
final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Access.class );
|
final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Access.class );
|
||||||
AccessType forcedAccessType = null;
|
AccessType forcedAccessType = null;
|
||||||
if ( accessAnnotationMirror != null ) {
|
if ( accessAnnotationMirror != null ) {
|
||||||
Element accessElement = ( Element ) TypeUtils.getAnnotationValue(
|
Element accessElement = (Element) TypeUtils.getAnnotationValue(
|
||||||
accessAnnotationMirror,
|
accessAnnotationMirror,
|
||||||
DEFAULT_ANNOTATION_PARAMETER_NAME
|
DEFAULT_ANNOTATION_PARAMETER_NAME
|
||||||
);
|
);
|
||||||
|
@ -415,7 +406,7 @@ public class TypeUtils {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitDeclared(DeclaredType declaredType, Element element) {
|
public String visitDeclared(DeclaredType declaredType, Element element) {
|
||||||
TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType );
|
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
||||||
String fqNameOfReturnType = null;
|
String fqNameOfReturnType = null;
|
||||||
if ( containsAnnotation( returnedElement, Embeddable.class ) ) {
|
if ( containsAnnotation( returnedElement, Embeddable.class ) ) {
|
||||||
fqNameOfReturnType = returnedElement.getQualifiedName().toString();
|
fqNameOfReturnType = returnedElement.getQualifiedName().toString();
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.jpamodelgen.test.typedmappedsuperclass;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public abstract class AttachmentGroup<GroupType extends AttachmentGroup, PostType extends AttachmentGroupPost<UserRoleType, GroupType>, UserRoleType extends UserRole> {
|
||||||
|
@OneToMany(mappedBy = "parentGroup")
|
||||||
|
protected Set<PostType> posts;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
long id;
|
||||||
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.jpamodelgen.test.typedmappedsuperclass;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class AttachmentGroupInTopic
|
||||||
|
extends AttachmentGroup<AttachmentGroupInTopic, AttachmentGroupPostInTopic, UserRole> {
|
||||||
|
public AttachmentGroupInTopic() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.jpamodelgen.test.typedmappedsuperclass;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public abstract class AttachmentGroupPost<UserRoleType extends UserRole, GroupType extends AttachmentGroup>
|
||||||
|
extends Post<UserRoleType> {
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.jpamodelgen.test.typedmappedsuperclass;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class AttachmentGroupPostInTopic extends AttachmentGroupPost<UserRole, AttachmentGroupInTopic> {
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.jpamodelgen.test.typedmappedsuperclass;
|
||||||
|
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public abstract class Post<UserRoleType extends UserRole> {
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.typedmappedsuperclass;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import org.hibernate.jpamodelgen.test.util.CompilationTest;
|
||||||
|
|
||||||
|
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Hardy Ferentschik
|
||||||
|
* @see METAGEN-37
|
||||||
|
*/
|
||||||
|
public class TypesMappedSuperclassTest extends CompilationTest {
|
||||||
|
@Test
|
||||||
|
public void testExtractClosestRealType() {
|
||||||
|
assertMetamodelClassGeneratedFor( AttachmentGroup.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPackageNameOfCurrentTest() {
|
||||||
|
return TypesMappedSuperclassTest.class.getPackage().getName();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.jpamodelgen.test.typedmappedsuperclass;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class UserRole {
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue