METAGEN-20 support raw collections and honor targetEntity

This commit is contained in:
Emmanuel Bernard 2010-01-22 18:38:53 +00:00 committed by Strong Liu
parent d4dac16e32
commit b78ebb332c
6 changed files with 249 additions and 11 deletions

View File

@ -79,8 +79,7 @@ public class TypeUtils {
public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
if ( type instanceof TypeVariable ) {
final TypeMirror compositeUpperBound = ( ( TypeVariable ) type ).getUpperBound();
final Types types = context.getProcessingEnvironment()
.getTypeUtils();
final Types types = context.getProcessingEnvironment().getTypeUtils();
final List<? extends TypeMirror> upperBounds = types.directSupertypes( compositeUpperBound );
if (upperBounds.size() == 0) {
return compositeUpperBound.toString();
@ -89,7 +88,6 @@ public class TypeUtils {
//take the first one
return extractClosestRealTypeAsString( upperBounds.get( 0 ), context );
}
}
else {
return type.toString();

View File

@ -22,8 +22,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
@ -43,7 +45,11 @@ import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import javax.tools.Diagnostic;
@ -348,8 +354,11 @@ public class AnnotationMetaEntity implements MetaEntity {
String fqElementName = returnedElement.getQualifiedName()
.toString(); // WARNING: .toString() is necessary here since Name equals does not compare to String
String collection = COLLECTIONS.get( fqElementName );
final List<? extends AnnotationMirror> annotations = element.getAnnotationMirrors();
String targetEntity = getTargetEntity( annotations );
if ( collection != null ) {
if ( element.getAnnotation( ElementCollection.class ) != null ) {
if ( containsAnnotation( annotations, ElementCollection.class ) ) {
//FIXME I don't understand why this code is different between Elementcollection and a regular collection but it needs to take targetClass into account
TypeMirror collectionElementType = getCollectionElementType( t, fqElementName );
final TypeElement collectionElement = ( TypeElement ) context.getProcessingEnvironment()
.getTypeUtils()
@ -361,11 +370,12 @@ public class AnnotationMetaEntity implements MetaEntity {
}
if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) {
return new AnnotationMetaMap(
parent, element, collection, getKeyType( t ), getElementType( t )
//FIXME support targetEntity for map's key @MapKeyClass
parent, element, collection, getKeyType( t ), getElementType( t, targetEntity )
);
}
else {
return new AnnotationMetaCollection( parent, element, collection, getElementType( t ) );
return new AnnotationMetaCollection( parent, element, collection, getElementType( t, targetEntity ) );
}
}
else {
@ -414,6 +424,63 @@ public class AnnotationMetaEntity implements MetaEntity {
}
}
private boolean containsAnnotation(List<? extends AnnotationMirror> annotations, Class<?> annotation) {
String annString = annotation.getName();
for ( AnnotationMirror mirror : annotations ) {
if ( annString.equals( mirror.getAnnotationType().toString() ) ) {
return true;
}
}
return false;
}
/**
* Returns targetEntity or null if no targetEntity is here or if equals to void
*/
private String getTargetEntity(List<? extends AnnotationMirror> annotations) {
final String elementCollection = ElementCollection.class.getName();
for ( AnnotationMirror mirror : annotations ) {
final String annotation = mirror.getAnnotationType().toString();
if ( elementCollection.equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( OneToMany.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( ManyToMany.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( ManyToOne.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
else if ( OneToOne.class.getName().equals( annotation ) ) {
final String targetEntity = getTargetEntity( mirror );
if (targetEntity != null) return targetEntity;
}
}
return null;
}
private String getTargetEntity(AnnotationMirror mirror) {
String targetEntity = null;
final Map<? extends ExecutableElement, ? extends AnnotationValue> attributes = mirror.getElementValues();
for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : attributes.entrySet() ) {
final String simpleName = entry.getKey().getSimpleName().toString();
if ( "targetEntity".equals( simpleName ) ) {
targetEntity = entry.getValue().toString();
break;
}
}
targetEntity = ( "void.class".equals( targetEntity ) ) ? null : targetEntity;
return targetEntity != null && targetEntity.endsWith( ".class" ) ?
targetEntity.substring( 0, targetEntity.length() - 6 ) : null;
}
public String generateImports() {
return importContext.generateImports();
}
@ -438,13 +505,23 @@ public class AnnotationMetaEntity implements MetaEntity {
return TypeUtils.extractClosestRealTypeAsString( t.getTypeArguments().get( 0 ), context );
}
private String getElementType(DeclaredType declaredType) {
if ( declaredType.getTypeArguments().size() == 1 ) {
final TypeMirror type = declaredType.getTypeArguments().get( 0 );
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 {
return TypeUtils.extractClosestRealTypeAsString( declaredType.getTypeArguments().get( 1 ), context );
//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 "?";
}
}

View File

@ -56,7 +56,7 @@ public class Parent {
this.name = name;
}
@OneToMany
@OneToMany(targetEntity = void.class)
@JoinColumn(name="parent_fk", nullable = false)
public Set<Child> getChildren() {
return children;

View File

@ -0,0 +1,68 @@
package org.hibernate.jpamodelgen.test.rawTypes;
import java.util.Collection;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* @author Emmanuel Bernard
*/
@Entity
public class A implements java.io.Serializable {
@Id
protected String id;
@Basic
protected String name;
@Basic
protected int value;
public A() {
}
@ManyToMany(targetEntity = B.class, cascade = CascadeType.ALL)
@JoinTable(name = "tbl_A_B",
joinColumns =
@JoinColumn(
name = "A_FK", referencedColumnName = "ID"),
inverseJoinColumns =
@JoinColumn(
name = "B_FK", referencedColumnName = "ID")
)
protected Collection bCol = new java.util.ArrayList();
public Collection getBCol() {
return bCol;
}
public void setBCol(Collection bCol) {
this.bCol = bCol;
}
public String getAId() {
return id;
}
public String getAName() {
return name;
}
public void setAName(String aName) {
this.name = aName;
}
public int getAValue() {
return value;
}
}

View File

@ -0,0 +1,54 @@
package org.hibernate.jpamodelgen.test.rawTypes;
import java.util.Collection;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* @author Emmanuel Bernard
*/
@Entity
public class B implements java.io.Serializable {
@Id
protected String id;
@Basic
protected String name;
@Basic
protected int value;
@ManyToMany(targetEntity = A.class, mappedBy = "bCol", cascade = CascadeType.ALL)
protected Collection aCol = new java.util.ArrayList();
public B() {
}
public Collection getACol() {
return aCol;
}
public void setACol(Collection aCol) {
this.aCol = aCol;
}
public String getBId() {
return id;
}
public String getBName() {
return name;
}
public int getBValue() {
return value;
}
}

View File

@ -0,0 +1,41 @@
// $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.rawTypes;
import org.testng.annotations.Test;
import org.hibernate.jpamodelgen.test.util.CompilationTest;
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertClassGenerated;
/**
* @author Emmanuel Bernard
*/
public class RawTypesTest extends CompilationTest {
@Test
public void testGenerics() {
assertClassGenerated( A.class.getName() + "_" );
assertClassGenerated( B.class.getName() + "_" );
}
@Override
protected String getTestPackage() {
return A.class.getPackage().getName();
}
}