From 813339a647d23ead6f4df13f4eefc959d45a5eeb Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Mon, 1 Feb 2010 20:49:09 +0000 Subject: [PATCH] METAGEN-9 Extended infrastructure to allow the specification of persistence.xml --- tooling/metamodel-generator/pom.xml | 12 + .../jpamodelgen/AccessTypeInformation.java | 90 +++ .../hibernate/jpamodelgen/ClassWriter.java | 7 +- .../org/hibernate/jpamodelgen/Context.java | 175 +++-- .../jpamodelgen/ImportContextImpl.java | 134 ++-- .../JPAMetaModelEntityProcessor.java | 211 ++++- .../annotation/AnnotationEmbeddable.java | 69 ++ .../annotation/AnnotationMetaAttribute.java | 14 +- .../annotation/AnnotationMetaCollection.java | 2 +- .../annotation/AnnotationMetaEntity.java | 726 +++++++----------- .../AnnotationMetaSingleAttribute.java | 2 +- .../{ => model}/ImportContext.java | 3 +- .../{ => model}/MetaAttribute.java | 2 +- .../{ => model}/MetaCollection.java | 2 +- .../jpamodelgen/{ => model}/MetaEntity.java | 22 +- .../{ => model}/MetaSingleAttribute.java | 2 +- .../hibernate/jpamodelgen/util/Constants.java | 69 ++ .../jpamodelgen/util/StringUtil.java | 77 ++ .../hibernate/jpamodelgen/util/TypeUtils.java | 234 +++++- .../jpamodelgen/xml/XmlMetaAttribute.java | 13 +- .../jpamodelgen/xml/XmlMetaCollection.java | 2 +- .../jpamodelgen/xml/XmlMetaEmbeddable.java | 69 ++ .../jpamodelgen/xml/XmlMetaEntity.java | 459 +++++++---- .../xml/XmlMetaMappedSuperClass.java | 74 ++ .../xml/XmlMetaSingleAttribute.java | 2 +- .../hibernate/jpamodelgen/xml/XmlParser.java | 264 +++++-- .../test/accesstype/AccessTypeTest.java | 20 +- .../jpamodelgen/test/accesstype/Order.java | 1 - .../jpamodelgen/test/arraytype/ArrayTest.java | 2 +- .../test/arraytype/TemperatureSamples.java | 2 +- .../ElementCollectionTest.java | 4 +- .../test/generics/GenericsTest.java | 4 +- .../test/inheritance/InheritanceTest.java | 4 +- .../jpamodelgen/test/mixedmode/Car.java | 42 + .../test/mixedmode/Coordinates.java | 31 + .../jpamodelgen/test/mixedmode/Insurance.java | 47 ++ .../jpamodelgen/test/mixedmode/Location.java | 73 ++ .../mixedmode/MixedConfigurationTest.java | 111 +++ .../jpamodelgen/test/mixedmode/Person.java | 49 ++ .../jpamodelgen/test/mixedmode/RentalCar.java | 71 ++ .../test/mixedmode/RentalCompany.java | 50 ++ .../jpamodelgen/test/mixedmode/Truck.java | 41 + .../jpamodelgen/test/mixedmode/Vehicle.java | 43 ++ .../test/mixedmode/XmlMetaCompleteTest.java | 53 ++ .../test/mixedmode/ZeroCoordinates.java | 41 + .../DeskWithRawType.java | 2 +- .../EmployeeWithRawType.java | 2 +- .../{rawTypes => rawtypes}/RawTypesTest.java | 6 +- .../test/util/CompilationTest.java | 86 ++- .../jpamodelgen/test/util/TestUtil.java | 55 +- .../test/xmlmapped/IgnoreInvalidXmlTest.java | 57 ++ .../test/xmlmapped/LivingBeing.java | 6 +- .../test/xmlmapped/XmlMappingTest.java | 20 +- .../test/resources/META-INF/persistence.xml | 11 +- .../src/test/resources/log4j.properties | 24 + .../jpamodelgen/test/accesstype}/orm.xml | 2 - .../jpamodelgen/test/mixedmode/car.xml | 17 + .../test/mixedmode/coordinates.xml | 22 + .../jpamodelgen/test/mixedmode/orm.xml | 18 + .../jpamodelgen/test/mixedmode/rentalcar.xml | 16 + .../jpamodelgen/test/mixedmode/truck.xml | 17 + .../jpamodelgen/test/xmlmapped}/jpa1-orm.xml | 0 .../test/xmlmapped/malformed-mapping.xml} | 0 .../jpamodelgen/test/xmlmapped/mammal.xml | 2 +- .../test/xmlmapped/non-existend-class.xml} | 0 .../test/xmlmapped/persistence.xml | 11 + .../src/test/suite/unit-tests.xml | 3 +- 67 files changed, 2884 insertions(+), 918 deletions(-) create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/AccessTypeInformation.java create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java rename tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/{ => model}/ImportContext.java (94%) rename tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/{ => model}/MetaAttribute.java (95%) rename tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/{ => model}/MetaCollection.java (95%) rename tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/{ => model}/MetaEntity.java (75%) rename tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/{ => model}/MetaSingleAttribute.java (95%) create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/StringUtil.java create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Car.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Insurance.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Person.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCar.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCompany.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Truck.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Vehicle.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/XmlMetaCompleteTest.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java rename tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/{rawTypes => rawtypes}/DeskWithRawType.java (96%) rename tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/{rawTypes => rawtypes}/EmployeeWithRawType.java (94%) rename tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/{rawTypes => rawtypes}/RawTypesTest.java (88%) create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/IgnoreInvalidXmlTest.java create mode 100644 tooling/metamodel-generator/src/test/resources/log4j.properties rename tooling/metamodel-generator/src/test/resources/{META-INF => org/hibernate/jpamodelgen/test/accesstype}/orm.xml (94%) create mode 100644 tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/car.xml create mode 100644 tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml create mode 100644 tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml create mode 100644 tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/rentalcar.xml create mode 100644 tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/truck.xml rename tooling/metamodel-generator/src/test/resources/{META-INF => org/hibernate/jpamodelgen/test/xmlmapped}/jpa1-orm.xml (100%) rename tooling/metamodel-generator/src/test/resources/{META-INF/malformed-mapping-xml.xml => org/hibernate/jpamodelgen/test/xmlmapped/malformed-mapping.xml} (100%) rename tooling/metamodel-generator/src/test/resources/{META-INF/dummy.xml => org/hibernate/jpamodelgen/test/xmlmapped/non-existend-class.xml} (100%) create mode 100644 tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/persistence.xml diff --git a/tooling/metamodel-generator/pom.xml b/tooling/metamodel-generator/pom.xml index 8d0ade3040..4dac279a2d 100644 --- a/tooling/metamodel-generator/pom.xml +++ b/tooling/metamodel-generator/pom.xml @@ -24,6 +24,17 @@ jdk15 test + + org.slf4j + slf4j-api + 1.5.6 + + + org.slf4j + slf4j-log4j12 + test + 1.5.6 + @@ -150,6 +161,7 @@ maven-surefire-plugin 2.4.3 + true sourceBaseDir diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/AccessTypeInformation.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/AccessTypeInformation.java new file mode 100644 index 0000000000..1ea408f75c --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/AccessTypeInformation.java @@ -0,0 +1,90 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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; + +import javax.persistence.AccessType; + +/** + * Encapsulates the access type information for a single class. + * + * @author Hardy Ferentschik + */ +public class AccessTypeInformation { + private final String fqcn; + + /** + * Access type explicitly specified in xml or on an entity. + */ + private AccessType explicitAccessType; + + /** + * The default type for en entity. This type might change during the parsing/discovering process. The reason + * for that is the ability to mix and match xml and annotation configuration. + */ + private AccessType defaultAccessType; + + private static final AccessType DEFAULT_ACCESS_TYPE = AccessType.PROPERTY; + + public AccessTypeInformation(String fqcn, AccessType explicitAccessType, AccessType defaultAccessType) { + this.fqcn = fqcn; + this.explicitAccessType = explicitAccessType; + this.defaultAccessType = defaultAccessType; + } + + public boolean isAccessTypeResolved() { + return explicitAccessType != null || defaultAccessType != null; + } + + public AccessType getAccessType() { + if ( explicitAccessType != null ) { + return explicitAccessType; + } + else if ( defaultAccessType != null ) { + return defaultAccessType; + + } + else { + return DEFAULT_ACCESS_TYPE; + } + } + + public void setDefaultAccessType(AccessType defaultAccessType) { + this.defaultAccessType = defaultAccessType; + } + + public void setExplicitAccessType(AccessType explicitAccessType) { + this.explicitAccessType = explicitAccessType; + } + + public AccessType getDefaultAccessType() { + return defaultAccessType; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "AccessTypeInformation" ); + sb.append( "{fqcn='" ).append( fqcn ).append( '\'' ); + sb.append( ", explicitAccessType=" ).append( explicitAccessType ); + sb.append( ", defaultAccessType=" ).append( defaultAccessType ); + sb.append( '}' ); + return sb.toString(); + } +} + + diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java index 0376cc1edb..01d668db12 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java @@ -31,6 +31,9 @@ import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.FileObject; +import org.hibernate.jpamodelgen.model.MetaAttribute; +import org.hibernate.jpamodelgen.model.MetaEntity; + /** * @author Emmanuel Bernard */ @@ -112,8 +115,8 @@ public class ClassWriter { //F..king Ch...t Have those people used their horrible APIs even once? final Element superClassElement = ( ( DeclaredType ) superClass ).asElement(); String superClassName = ( ( TypeElement ) superClassElement ).getQualifiedName().toString(); - if ( context.getMetaEntitiesToProcess().containsKey( superClassName ) - || context.getMetaSuperclassAndEmbeddableToProcess().containsKey( superClassName ) ) { + if ( context.containsMetaEntity( superClassName ) + || context.containsMetaSuperclassOrEmbeddable( superClassName ) ) { pw.print( " extends " + superClassName + "_" ); } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java index 3190c05a4c..4181dd76e1 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java @@ -17,17 +17,20 @@ */ package org.hibernate.jpamodelgen; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; +import java.util.List; import java.util.Map; -import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; import javax.persistence.AccessType; import javax.tools.Diagnostic; -import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity; -import org.hibernate.jpamodelgen.util.TypeUtils; +import org.hibernate.jpamodelgen.model.MetaEntity; /** * @author Max Andersen @@ -35,84 +38,115 @@ import org.hibernate.jpamodelgen.util.TypeUtils; * @author Emmanuel Bernard */ public class Context { + private static final String PATH_SEPARATOR = System.getProperty( "file.separator" ); + private static final String DEFAULT_PERSISTENCE_XML_LOCATION = "/META-INF/persistence.xml"; + private final Map metaEntities = new HashMap(); + private final Map metaSuperclassAndEmbeddable = new HashMap(); + private final Map accessTypeInformation = new HashMap(); - private final Map metaEntitiesToProcess = new HashMap(); - private final Map metaSuperclassAndEmbeddableToProcess = new HashMap(); + private final ProcessingEnvironment pe; + private final boolean logDebug; + private final String persistenceXmlLocation; - private ProcessingEnvironment pe; - private boolean logDebug = false; - - //used to cache access types - private Map accessTypes = new HashMap(); - private Set elementsAlreadyProcessed = new HashSet(); - - private static class AccessTypeHolder { - public AccessType elementAccessType; - public AccessType hierarchyAccessType; - } + private final List ormXmlFiles; + private boolean isPersistenceUnitCompletelyXmlConfigured; + private AccessType persistenceUnitDefaultAccessType; public Context(ProcessingEnvironment pe) { this.pe = pe; - String debugParam = pe.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ); - if ( debugParam != null && "true".equals( debugParam ) ) { - logDebug = true; + + if ( pe.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION ) != null ) { + String tmp = pe.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION ); + if ( !tmp.startsWith( PATH_SEPARATOR ) ) { + tmp = PATH_SEPARATOR + tmp; + } + persistenceXmlLocation = tmp; } + else { + persistenceXmlLocation = DEFAULT_PERSISTENCE_XML_LOCATION; + } + + if ( pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION ) != null ) { + String tmp = pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION ); + ormXmlFiles = new ArrayList(); + for ( String ormFile : tmp.split( "," ) ) { + if ( !ormFile.startsWith( PATH_SEPARATOR ) ) { + ormFile = PATH_SEPARATOR + ormFile; + } + ormXmlFiles.add( ormFile ); + } + } + else { + ormXmlFiles = Collections.emptyList(); + } + + logDebug = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ) ); + } public ProcessingEnvironment getProcessingEnvironment() { return pe; } - public Map getMetaEntitiesToProcess() { - return metaEntitiesToProcess; + public Elements getElementUtils() { + return pe.getElementUtils(); } - public Map getMetaSuperclassAndEmbeddableToProcess() { - return metaSuperclassAndEmbeddableToProcess; + public Types getTypeUtils() { + return pe.getTypeUtils(); } - public void addAccessType(TypeElement element, AccessType accessType) { - AccessTypeHolder typeHolder = accessTypes.get( element ); - if ( typeHolder == null ) { - typeHolder = new AccessTypeHolder(); - accessTypes.put( element, typeHolder ); - } - typeHolder.elementAccessType = accessType; + public String getPersistenceXmlLocation() { + return persistenceXmlLocation; } - public void addAccessTypeForHierarchy(TypeElement element, AccessType accessType) { - AccessTypeHolder typeHolder = accessTypes.get( element ); - if ( typeHolder == null ) { - typeHolder = new AccessTypeHolder(); - accessTypes.put( element, typeHolder ); - } - typeHolder.hierarchyAccessType = accessType; + public List getOrmXmlFiles() { + return ormXmlFiles; } - public AccessType getAccessType(TypeElement element) { - final AccessTypeHolder typeHolder = accessTypes.get( element ); - return typeHolder != null ? typeHolder.elementAccessType : null; + public boolean containsMetaEntity(String fqcn) { + return metaEntities.containsKey( fqcn ); } - public AccessType getDefaultAccessTypeForHerarchy(TypeElement element) { - final AccessTypeHolder typeHolder = accessTypes.get( element ); - return typeHolder != null ? typeHolder.hierarchyAccessType : null; + public MetaEntity getMetaEntity(String fqcn) { + return metaEntities.get( fqcn ); } - public Set getElementsAlreadyProcessed() { - return elementsAlreadyProcessed; + public Collection getMetaEntities() { + return metaEntities.values(); } - //only process Embeddable or Superclass - //does not work for Entity (risk of circularity) - public void processElement(TypeElement element, AccessType defaultAccessTypeForHierarchy) { - if ( elementsAlreadyProcessed.contains( element.getQualifiedName().toString() ) ) { - logMessage( Diagnostic.Kind.OTHER, "Element already processed (ignoring): " + element ); - return; - } - ClassWriter.writeFile( new AnnotationMetaEntity( element, this, defaultAccessTypeForHierarchy ), this ); - TypeUtils.extractClosestRealTypeAsString( element.asType(), this ); - elementsAlreadyProcessed.add( element.getQualifiedName().toString() ); + public void addMetaEntity(String fcqn, MetaEntity metaEntity) { + metaEntities.put( fcqn, metaEntity ); + } + + public boolean containsMetaSuperclassOrEmbeddable(String fqcn) { + return metaSuperclassAndEmbeddable.containsKey( fqcn ); + } + + public MetaEntity getMetaSuperclassOrEmbeddable(String fqcn) { + return metaSuperclassAndEmbeddable.get( fqcn ); + } + + public void addMetaSuperclassOrEmbeddable(String fcqn, MetaEntity metaEntity) { + metaSuperclassAndEmbeddable.put( fcqn, metaEntity ); + } + + public Collection getMetaSuperclassOrEmbeddable() { + return metaSuperclassAndEmbeddable.values(); + } + + public void addAccessTypeInformation(String fqcn, AccessTypeInformation info) { + accessTypeInformation.put( fqcn, info ); + } + + public AccessTypeInformation getAccessTypeInfo(String fqcn) { + return accessTypeInformation.get( fqcn ); + } + + public TypeElement getTypeElementForFullyQualifiedName(String fqcn) { + Elements elementUtils = pe.getElementUtils(); + return elementUtils.getTypeElement( fqcn ); } public void logMessage(Diagnostic.Kind type, String message) { @@ -121,4 +155,33 @@ public class Context { } pe.getMessager().printMessage( type, message ); } + + public boolean isPersistenceUnitCompletelyXmlConfigured() { + return isPersistenceUnitCompletelyXmlConfigured; + } + + public void setPersistenceUnitCompletelyXmlConfigured(boolean persistenceUnitCompletelyXmlConfigured) { + isPersistenceUnitCompletelyXmlConfigured = persistenceUnitCompletelyXmlConfigured; + } + + public AccessType getPersistenceUnitDefaultAccessType() { + return persistenceUnitDefaultAccessType; + } + + public void setPersistenceUnitDefaultAccessType(AccessType persistenceUnitDefaultAccessType) { + this.persistenceUnitDefaultAccessType = persistenceUnitDefaultAccessType; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "Context" ); + sb.append( "{accessTypeInformation=" ).append( accessTypeInformation ); + sb.append( ", logDebug=" ).append( logDebug ); + sb.append( ", isPersistenceUnitCompletelyXmlConfigured=" ).append( isPersistenceUnitCompletelyXmlConfigured ); + sb.append( ", ormXmlFiles=" ).append( ormXmlFiles ); + sb.append( ", persistenceXmlLocation='" ).append( persistenceXmlLocation ).append( '\'' ); + sb.append( '}' ); + return sb.toString(); + } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContextImpl.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContextImpl.java index 0a705a193c..5c5511de8a 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContextImpl.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContextImpl.java @@ -18,14 +18,14 @@ package org.hibernate.jpamodelgen; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeSet; +import org.hibernate.jpamodelgen.model.ImportContext; + /** - * * @author Max Andersen * @author Hardy Ferentschik * @author Emmanuel Bernard @@ -35,10 +35,11 @@ public class ImportContextImpl implements ImportContext { Set imports = new TreeSet(); Set staticImports = new TreeSet(); Map simpleNames = new HashMap(); - + String basePackage = ""; private static final Map PRIMITIVES = new HashMap(); + static { PRIMITIVES.put( "char", "Character" ); @@ -61,77 +62,81 @@ public class ImportContextImpl implements ImportContext { /** * Add fqcn to the import list. Returns fqcn as needed in source code. * Attempts to handle fqcn with array and generics references. - * + *

* e.g. * java.util.Collection imports java.util.Collection and returns Collection * org.marvel.Hulk[] imports org.marvel.Hulk and returns Hulk - * - * - * @param fqcn + * + * @param fqcn Fully qualified class name + * * @return import string */ public String importType(String fqcn) { - String result = fqcn; - + String result = fqcn; + //if(fqcn==null) return "/** (null) **/"; - + String additionalTypePart = null; - if(fqcn.indexOf('<')>=0) { - additionalTypePart = result.substring(fqcn.indexOf('<')); - result = result.substring(0,fqcn.indexOf('<')); - fqcn = result; - } else if(fqcn.indexOf('[')>=0) { - additionalTypePart = result.substring(fqcn.indexOf('[')); - result = result.substring(0,fqcn.indexOf('[')); + if ( fqcn.indexOf( '<' ) >= 0 ) { + additionalTypePart = result.substring( fqcn.indexOf( '<' ) ); + result = result.substring( 0, fqcn.indexOf( '<' ) ); fqcn = result; } - + else if ( fqcn.indexOf( '[' ) >= 0 ) { + additionalTypePart = result.substring( fqcn.indexOf( '[' ) ); + result = result.substring( 0, fqcn.indexOf( '[' ) ); + fqcn = result; + } + String pureFqcn = fqcn.replace( '$', '.' ); - - boolean canBeSimple = true; - - - String simpleName = unqualify(fqcn); - if(simpleNames.containsKey(simpleName)) { - String existingFqcn = simpleNames.get(simpleName); - if(existingFqcn.equals(pureFqcn)) { + + boolean canBeSimple; + + String simpleName = unqualify( fqcn ); + if ( simpleNames.containsKey( simpleName ) ) { + String existingFqcn = simpleNames.get( simpleName ); + if ( existingFqcn.equals( pureFqcn ) ) { canBeSimple = true; - } else { + } + else { canBeSimple = false; } - } else { + } + else { canBeSimple = true; - simpleNames.put(simpleName, pureFqcn); + simpleNames.put( simpleName, pureFqcn ); imports.add( pureFqcn ); } - - - if ( inSamePackage(fqcn) || (imports.contains( pureFqcn ) && canBeSimple) ) { - result = unqualify( result ); // dequalify - } else if ( inJavaLang( fqcn ) ) { + + + if ( inSamePackage( fqcn ) || ( imports.contains( pureFqcn ) && canBeSimple ) ) { + result = unqualify( result ); // de-qualify + } + else if ( inJavaLang( fqcn ) ) { result = result.substring( "java.lang.".length() ); } - if(additionalTypePart!=null) { + if ( additionalTypePart != null ) { result = result + additionalTypePart; - } - + } + result = result.replace( '$', '.' ); - return result; + return result; } - + public String staticImport(String fqcn, String member) { String local = fqcn + "." + member; - imports.add(local); - staticImports.add(local); - - if(member.equals("*")) { + imports.add( local ); + staticImports.add( local ); + + if ( member.equals( "*" ) ) { return ""; - } else { + } + else { return member; } } - + private boolean inDefaultPackage(String className) { return className.indexOf( "." ) < 0; } @@ -143,7 +148,7 @@ public class ImportContextImpl implements ImportContext { private boolean inSamePackage(String className) { String other = qualifier( className ); return other == basePackage - || (other != null && other.equals( basePackage ) ); + || ( other != null && other.equals( basePackage ) ); } private boolean inJavaLang(String className) { @@ -152,33 +157,34 @@ public class ImportContextImpl implements ImportContext { public String generateImports() { StringBuffer buf = new StringBuffer(); - - for ( Iterator imps = imports.iterator(); imps.hasNext(); ) { - String next = imps.next(); - if(isPrimitive(next) || inDefaultPackage(next) || inJavaLang(next) || inSamePackage(next)) { - // dont add automatically "imported" stuff - } else { - if(staticImports.contains(next)) { - buf.append("import static " + next + ";\r\n"); - } else { - buf.append("import " + next + ";\r\n"); - } + + for ( String next : imports ) { + if ( isPrimitive( next ) || inDefaultPackage( next ) || inJavaLang( next ) || inSamePackage( next ) ) { + // dont add automatically "imported" stuff + } + else { + if ( staticImports.contains( next ) ) { + buf.append( "import static " + next + ";\r\n" ); } + else { + buf.append( "import " + next + ";\r\n" ); + } + } } - - if(buf.indexOf( "$" )>=0) { + + if ( buf.indexOf( "$" ) >= 0 ) { return buf.toString(); } - return buf.toString(); + return buf.toString(); } - + 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) { - int loc = qualifiedName.lastIndexOf("."); + int loc = qualifiedName.lastIndexOf( "." ); return ( loc < 0 ) ? "" : qualifiedName.substring( 0, loc ); } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java index 6c62769fe6..f8c19fb2da 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java @@ -17,6 +17,8 @@ */ package org.hibernate.jpamodelgen; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -29,12 +31,22 @@ 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.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.SimpleTypeVisitor6; import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; import javax.tools.Diagnostic; +import org.hibernate.jpamodelgen.annotation.AnnotationEmbeddable; import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity; +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.xml.XmlParser; @@ -49,9 +61,15 @@ import static javax.lang.model.SourceVersion.RELEASE_6; */ @SupportedAnnotationTypes("*") @SupportedSourceVersion(RELEASE_6) -@SupportedOptions({ JPAMetaModelEntityProcessor.DEBUG_OPTION }) +@SupportedOptions({ + JPAMetaModelEntityProcessor.DEBUG_OPTION, + JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION, + JPAMetaModelEntityProcessor.ORM_XML_OPTION +}) public class JPAMetaModelEntityProcessor extends AbstractProcessor { public static final String DEBUG_OPTION = "debug"; + public static final String PERSISTENCE_XML_OPTION = "persistenceXml"; + public static final String ORM_XML_OPTION = "ormXmlList"; private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = Boolean.FALSE; private boolean xmlProcessed = false; @@ -78,75 +96,190 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor { if ( !xmlProcessed ) { XmlParser parser = new XmlParser( context ); - parser.parsePersistenceXml(); + parser.parseXml(); xmlProcessed = true; } - if ( !hostJPAAnnotations( annotations ) ) { - context.logMessage( Diagnostic.Kind.OTHER, "Current processing round does not contain entities" ); + if ( context.isPersistenceUnitCompletelyXmlConfigured() ) { + context.logMessage( + Diagnostic.Kind.OTHER, + "Skipping the processing of annotations since persistence unit is purely xml configured." + ); return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS; } Set elements = roundEnvironment.getRootElements(); for ( Element element : elements ) { - context.logMessage( Diagnostic.Kind.OTHER, "Processing " + element.toString() ); - handleRootElementAnnotationMirrors( element ); + if ( isJPAEntity( element ) ) { + context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element.toString() ); + handleRootElementAnnotationMirrors( element ); + } } return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS; } private void createMetaModelClasses() { - for ( MetaEntity entity : context.getMetaEntitiesToProcess().values() ) { - context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for " + entity ); + for ( MetaEntity entity : context.getMetaEntities() ) { + context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for entity " + entity ); ClassWriter.writeFile( entity, context ); } - //process left over, in most cases is empty - for ( String className : context.getElementsAlreadyProcessed() ) { - context.getMetaSuperclassAndEmbeddableToProcess().remove( className ); - } - - for ( MetaEntity entity : context.getMetaSuperclassAndEmbeddableToProcess().values() ) { - context.logMessage( Diagnostic.Kind.OTHER, "Writing meta model for " + entity ); - ClassWriter.writeFile( entity, context ); + // we cannot process the delayed entities in any order. There might be dependencies between them. + // we need to process the top level entities first + // TODO make sure that we don't run into circular dependencies here + Collection toProcessEntities = context.getMetaSuperclassOrEmbeddable(); + while ( !toProcessEntities.isEmpty() ) { + Set processedEntities = new HashSet(); + for ( MetaEntity entity : toProcessEntities ) { + if ( containedInEntity( toProcessEntities, entity ) ) { + continue; + } + context.logMessage( + Diagnostic.Kind.OTHER, "Writing meta model for embeddable/mapped superclass" + entity + ); + ClassWriter.writeFile( entity, context ); + processedEntities.add( entity ); + } + toProcessEntities.removeAll( processedEntities ); } } - private boolean hostJPAAnnotations(Set annotations) { - for ( TypeElement type : annotations ) { - if ( TypeUtils.isTypeElementOfType( type, Entity.class ) ) { - return true; + private boolean containedInEntity(Collection entities, MetaEntity containedEntity) { + ContainsAttributeTypeVisitor visitor = new ContainsAttributeTypeVisitor( + containedEntity.getTypeElement(), context + ); + for ( MetaEntity entity : entities ) { + if ( entity.equals( containedEntity ) ) { + continue; } - else if ( TypeUtils.isTypeElementOfType( type, Embeddable.class ) ) { - return true; + for ( Element subElement : ElementFilter.fieldsIn( entity.getTypeElement().getEnclosedElements() ) ) { + TypeMirror mirror = subElement.asType(); + if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) { + continue; + } + boolean contains = mirror.accept( visitor, subElement ); + if ( contains ) { + return true; + } } - else if ( TypeUtils.isTypeElementOfType( type, MappedSuperclass.class ) ) { - return true; + for ( Element subElement : ElementFilter.methodsIn( entity.getTypeElement().getEnclosedElements() ) ) { + TypeMirror mirror = subElement.asType(); + if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) { + continue; + } + boolean contains = mirror.accept( visitor, subElement ); + if ( contains ) { + return true; + } } } return false; } + private boolean isJPAEntity(Element element) { + return TypeUtils.containsAnnotation( element, Entity.class, MappedSuperclass.class, Embeddable.class ); + } + private void handleRootElementAnnotationMirrors(final Element element) { - List annotationMirrors = element.getAnnotationMirrors(); - for ( AnnotationMirror mirror : annotationMirrors ) { - if ( element.getKind() == ElementKind.CLASS ) { - if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) { - AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context ); - // TODO instead of just adding the entity we have to do some merging. - context.getMetaEntitiesToProcess().put( metaEntity.getQualifiedName(), metaEntity ); - } - else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class ) - || TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) { - AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context ); - - // TODO instead of just adding the entity we have to do some merging. - context.getMetaSuperclassAndEmbeddableToProcess().put( metaEntity.getQualifiedName(), metaEntity ); - } + if ( !ElementKind.CLASS.equals( element.getKind() ) ) { + continue; } + + String fqn = ( ( TypeElement ) element ).getQualifiedName().toString(); + MetaEntity alreadyExistingMetaEntity = tryGettingExistingEntityFromContext( mirror, fqn ); + if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) { + String msg = "Skipping processing of annotations for " + fqn + " since xml configuration is metadata complete."; + context.logMessage( Diagnostic.Kind.OTHER, msg ); + continue; + } + + AnnotationMetaEntity metaEntity; + if ( TypeUtils.containsAnnotation( element, Embeddable.class ) ) { + metaEntity = new AnnotationEmbeddable( ( TypeElement ) element, context ); + } + else { + metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context ); + } + + if ( alreadyExistingMetaEntity != null ) { + metaEntity.mergeInMembers( alreadyExistingMetaEntity.getMembers() ); + } + addMetaEntityToContext( mirror, metaEntity ); + } + } + + private MetaEntity tryGettingExistingEntityFromContext(AnnotationMirror mirror, String fqn) { + MetaEntity alreadyExistingMetaEntity = null; + if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) { + alreadyExistingMetaEntity = context.getMetaEntity( fqn ); + } + else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class ) + || TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) { + alreadyExistingMetaEntity = context.getMetaSuperclassOrEmbeddable( fqn ); + } + return alreadyExistingMetaEntity; + } + + private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) { + if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) { + context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity ); + } + else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class ) ) { + context.addMetaSuperclassOrEmbeddable( metaEntity.getQualifiedName(), metaEntity ); + } + else if ( TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) { + context.addMetaSuperclassOrEmbeddable( metaEntity.getQualifiedName(), metaEntity ); + } + } + + + class ContainsAttributeTypeVisitor extends SimpleTypeVisitor6 { + + private Context context; + private TypeElement type; + + ContainsAttributeTypeVisitor(TypeElement elem, Context context) { + this.context = context; + this.type = elem; + } + + @Override + public Boolean visitDeclared(DeclaredType declaredType, Element element) { + TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType ); + + String fqNameOfReturnType = returnedElement.getQualifiedName().toString(); + String collection = Constants.COLLECTIONS.get( fqNameOfReturnType ); + if ( collection != null ) { + TypeMirror collectionElementType = TypeUtils.getCollectionElementType( + declaredType, fqNameOfReturnType, null, context + ); + returnedElement = ( TypeElement ) context.getTypeUtils().asElement( collectionElementType ); + } + + if ( type.getQualifiedName().toString().equals( returnedElement.getQualifiedName().toString() ) ) { + return Boolean.TRUE; + } + else { + return Boolean.FALSE; + } + } + + @Override + public Boolean visitExecutable(ExecutableType t, Element element) { + if ( !element.getKind().equals( ElementKind.METHOD ) ) { + return Boolean.FALSE; + } + + String string = element.getSimpleName().toString(); + if ( !StringUtil.isPropertyName( string ) ) { + return Boolean.FALSE; + } + + TypeMirror returnType = t.getReturnType(); + return returnType.accept( this, element ); } } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java new file mode 100644 index 0000000000..074d14e814 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationEmbeddable.java @@ -0,0 +1,69 @@ +// $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.annotation; + +import java.util.List; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; + +import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.model.MetaAttribute; + +/** + * @author Max Andersen + * @author Hardy Ferentschik + * @author Emmanuel Bernard + */ +public class AnnotationEmbeddable extends AnnotationMetaEntity { + + // Embeddables needs to be lazily initialized since the access type be determined by the class which is embedding + // the entity. This might not be known until annotations are processed. + // Also note, that if two different classes with different access types embed this entity the access type of the + // embeddable will be the one of the last embedding entity processed. The result is not determined (that's ok + // according to the spec) + private boolean initialized; + + public AnnotationEmbeddable(TypeElement element, Context context) { + super( element, context, true ); + } + + public List getMembers() { + if ( !initialized ) { + context.logMessage( Diagnostic.Kind.OTHER, "Entity " + getQualifiedName() + "was lazily initialised." ); + init(); + initialized = true; + } + return super.getMembers(); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "AnnotationEmbeddable" ); + sb.append( "{element=" ).append( element ); + sb.append( ", members=" ); + if ( initialized ) { + sb.append( members ); + } + else { + sb.append( "[un-initalized]" ); + } + sb.append( '}' ); + return sb.toString(); + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java index 648ee6f565..04562bca6e 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaAttribute.java @@ -22,7 +22,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.util.Elements; -import org.hibernate.jpamodelgen.MetaAttribute; +import org.hibernate.jpamodelgen.model.MetaAttribute; /** * @author Max Andersen @@ -47,7 +47,7 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute { } public String getPropertyName() { - Elements elementsUtil = parent.getContext().getProcessingEnvironment().getElementUtils(); + Elements elementsUtil = parent.getContext().getElementUtils(); if ( element.getKind() == ElementKind.FIELD ) { return element.getSimpleName().toString(); } @@ -71,4 +71,14 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute { public String getTypeDeclaration() { return type; } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "AnnotationMetaAttribute" ); + sb.append( "{element=" ).append( element ); + sb.append( ", type='" ).append( type ).append( '\'' ); + sb.append( '}' ); + return sb.toString(); + } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaCollection.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaCollection.java index 326caae0ef..c1764e35cc 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaCollection.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaCollection.java @@ -19,7 +19,7 @@ package org.hibernate.jpamodelgen.annotation; import javax.lang.model.element.Element; -import org.hibernate.jpamodelgen.MetaCollection; +import org.hibernate.jpamodelgen.model.MetaCollection; /** * @author Max Andersen diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java index 0db7c62941..3d69c394d3 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaEntity.java @@ -18,6 +18,7 @@ package org.hibernate.jpamodelgen.annotation; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,31 +36,27 @@ import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; -import javax.lang.model.util.Elements; import javax.lang.model.util.SimpleTypeVisitor6; -import javax.persistence.Access; import javax.persistence.AccessType; +import javax.persistence.Basic; import javax.persistence.ElementCollection; import javax.persistence.Embeddable; -import javax.persistence.Embedded; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.Id; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.MapKeyClass; -import javax.persistence.MappedSuperclass; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Transient; import javax.tools.Diagnostic; +import org.hibernate.jpamodelgen.AccessTypeInformation; import org.hibernate.jpamodelgen.Context; -import org.hibernate.jpamodelgen.ImportContext; import org.hibernate.jpamodelgen.ImportContextImpl; -import org.hibernate.jpamodelgen.MetaAttribute; -import org.hibernate.jpamodelgen.MetaEntity; -import org.hibernate.jpamodelgen.MetaModelGenerationException; +import org.hibernate.jpamodelgen.model.ImportContext; +import org.hibernate.jpamodelgen.model.MetaAttribute; +import org.hibernate.jpamodelgen.model.MetaEntity; +import org.hibernate.jpamodelgen.util.Constants; +import org.hibernate.jpamodelgen.util.StringUtil; import org.hibernate.jpamodelgen.util.TypeUtils; /** @@ -69,32 +66,25 @@ import org.hibernate.jpamodelgen.util.TypeUtils; */ public class AnnotationMetaEntity implements MetaEntity { - private static final String DEFAULT_ANNOTATION_PARAMETER_NAME = "value"; - static Map COLLECTIONS = new HashMap(); + protected final ImportContext importContext; + protected final TypeElement element; + protected final Map members; + protected Context context; - static { - COLLECTIONS.put( "java.util.Collection", "javax.persistence.metamodel.CollectionAttribute" ); - COLLECTIONS.put( "java.util.Set", "javax.persistence.metamodel.SetAttribute" ); - COLLECTIONS.put( "java.util.List", "javax.persistence.metamodel.ListAttribute" ); - COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" ); - } - - private final TypeElement element; - private final ImportContext importContext; - private Context context; - //used to propagate the access type of the root entity over to subclasses, superclasses and embeddable - private AccessType defaultAccessTypeForHierarchy; - private AccessType defaultAccessTypeForElement; + private AccessTypeInformation entityAccessTypeInfo; public AnnotationMetaEntity(TypeElement element, Context context) { - this.element = element; - this.context = context; - importContext = new ImportContextImpl( getPackageName() ); + this( element, context, false ); } - public AnnotationMetaEntity(TypeElement element, Context context, AccessType accessType) { - this( element, context ); - this.defaultAccessTypeForHierarchy = accessType; + protected AnnotationMetaEntity(TypeElement element, Context context, boolean lazilyInitialised) { + this.element = element; + this.context = context; + this.members = new HashMap(); + this.importContext = new ImportContextImpl( getPackageName() ); + if ( !lazilyInitialised ) { + init(); + } } public Context getContext() { @@ -110,413 +100,65 @@ public class AnnotationMetaEntity implements MetaEntity { } public String getPackageName() { - PackageElement packageOf = context.getProcessingEnvironment().getElementUtils().getPackageOf( element ); - return context.getProcessingEnvironment().getElementUtils().getName( packageOf.getQualifiedName() ).toString(); + PackageElement packageOf = context.getElementUtils().getPackageOf( element ); + return context.getElementUtils().getName( packageOf.getQualifiedName() ).toString(); } public List getMembers() { - List membersFound = new ArrayList(); - final AccessType elementAccessType = getAccessTypeForElement(); - - List fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() ); - addPersistentMembers( membersFound, elementAccessType, fieldsOfClass, AccessType.FIELD ); - - List methodsOfClass = ElementFilter.methodsIn( element.getEnclosedElements() ); - addPersistentMembers( membersFound, elementAccessType, methodsOfClass, AccessType.PROPERTY ); - - //process superclasses - for ( TypeElement superclass = TypeUtils.getSuperclassTypeElement( element ); - superclass != null; - superclass = TypeUtils.getSuperclassTypeElement( superclass ) ) { - if ( TypeUtils.containsAnnotation( superclass, Entity.class ) ) { - break; //will be handled or has been handled already - } - else if ( TypeUtils.containsAnnotation( superclass, MappedSuperclass.class ) ) { - //FIXME use the class default access type - context.processElement( superclass, defaultAccessTypeForHierarchy ); - } - } - return membersFound; + return new ArrayList( members.values() ); } - private void addPersistentMembers( - List membersFound, - AccessType elementAccessType, - List membersOfClass, - AccessType membersKind) { - AccessType explicitAccessType; - if ( elementAccessType == membersKind ) { - //all membersKind considered - explicitAccessType = null; - } - else { - //use membersKind only if marked with @Access(membersKind) - explicitAccessType = membersKind; - } - for ( Element memberOfClass : membersOfClass ) { - - TypeVisitor visitor = new TypeVisitor( this, explicitAccessType ); - AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass ); - if ( result != null ) { - membersFound.add( result ); - } - } + @Override + public boolean isMetaComplete() { + return false; } - private AccessType getAccessTypeForElement() { - - //get local strategy - AccessType accessType = getAccessTypeForClass( element ); - if ( accessType == null ) { - accessType = this.defaultAccessTypeForHierarchy; + public void mergeInMembers(Collection attributes) { + for ( MetaAttribute attribute : attributes ) { + members.put( attribute.getPropertyName(), attribute ); } - if ( accessType == null ) { - //we don't know if an entity go up - // - //superclasses are always treated after their entities - //and their access type are discovered - //FIXME is it really true if only the superclass is changed - TypeElement superClass = element; - do { - superClass = TypeUtils.getSuperclassTypeElement( superClass ); - if ( superClass != null ) { - if ( TypeUtils.containsAnnotation( superClass, Entity.class, MappedSuperclass.class ) ) { - //FIXME make it work for XML - AccessType superClassAccessType = getAccessTypeForClass( superClass ); - //we've reach the root entity and resolved Ids - if ( superClassAccessType != null && defaultAccessTypeForHierarchy != null ) { - break; //we've found it - } - } - else { - break; //neither @Entity nor @MappedSuperclass - } - } - } - while ( superClass != null ); - } - - if ( accessType == null ) { - accessType = AccessType.PROPERTY; //default to property - this.defaultAccessTypeForElement = accessType; - } - //this is a subclass so caching is OK - //this.defaultAccessTypeForHierarchy = accessType; - context.addAccessType( this.element, accessType ); - this.defaultAccessTypeForElement = accessType; - return accessType; - } - - private AccessType getAccessTypeForClass(TypeElement searchedElement) { - context.logMessage( Diagnostic.Kind.OTHER, "check class " + searchedElement ); - AccessType accessType = context.getAccessType( searchedElement ); - - if ( defaultAccessTypeForHierarchy == null ) { - this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( searchedElement ); - } - if ( accessType != null ) { - context.logMessage( Diagnostic.Kind.OTHER, "Found in cache" + searchedElement + ":" + accessType ); - return accessType; - } - - /** - * when forcing access type, we can only override the defaultAccessTypeForHierarchy - * if we are the entity root (identified by having @Id or @EmbeddedId - */ - AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( searchedElement ); - if ( forcedAccessType != null ) { - context.logMessage( Diagnostic.Kind.OTHER, "access type " + searchedElement + ":" + forcedAccessType ); - context.addAccessType( searchedElement, forcedAccessType ); - } - - //continue nevertheless to check if we are root and if defaultAccessTypeForHierarchy - //should be overridden - if ( forcedAccessType == null || defaultAccessTypeForHierarchy == null ) { - List myMembers = searchedElement.getEnclosedElements(); - for ( Element subElement : myMembers ) { - List entityAnnotations = - context.getProcessingEnvironment().getElementUtils().getAllAnnotationMirrors( subElement ); - - for ( Object entityAnnotation : entityAnnotations ) { - AnnotationMirror annotationMirror = ( AnnotationMirror ) entityAnnotation; - - //FIXME consider XML - if ( TypeUtils.isAnnotationMirrorOfType( annotationMirror, Id.class ) - || TypeUtils.isAnnotationMirrorOfType( annotationMirror, EmbeddedId.class ) ) { - context.logMessage( Diagnostic.Kind.OTHER, "Found id on" + searchedElement ); - final ElementKind kind = subElement.getKind(); - if ( kind == ElementKind.FIELD || kind == ElementKind.METHOD ) { - accessType = kind == ElementKind.FIELD ? AccessType.FIELD : AccessType.PROPERTY; - //FIXME enlever in niveau - if ( defaultAccessTypeForHierarchy == null ) { - this.defaultAccessTypeForHierarchy = context.getDefaultAccessTypeForHerarchy( - searchedElement - ); - //we've discovered the class hierarchy, let's cache it - if ( defaultAccessTypeForHierarchy == null ) { - this.defaultAccessTypeForHierarchy = accessType; - context.addAccessTypeForHierarchy( searchedElement, defaultAccessTypeForHierarchy ); - //FIXME should we add - //context.addAccessTypeForHierarchy( element, defaultAccessTypeForHierarchy ); - } - } - if ( forcedAccessType == null ) { - context.addAccessType( searchedElement, accessType ); - context.logMessage( - Diagnostic.Kind.OTHER, "access type " + searchedElement + ":" + accessType - ); - return accessType; - } - else { - return forcedAccessType; - } - } - } - } - } - } - return forcedAccessType; - } - - private AccessType determineAnnotationSpecifiedAccessType(Element element) { - final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Access.class ); - AccessType forcedAccessType = null; - if ( accessAnnotationMirror != null ) { - Element accessElement = ( Element ) TypeUtils.getAnnotationValue( - accessAnnotationMirror, - DEFAULT_ANNOTATION_PARAMETER_NAME - ); - if ( accessElement.getKind().equals( ElementKind.ENUM_CONSTANT ) ) { - if ( accessElement.getSimpleName().toString().equals( AccessType.PROPERTY.toString() ) ) { - forcedAccessType = AccessType.PROPERTY; - } - else if ( accessElement.getSimpleName().toString().equals( AccessType.FIELD.toString() ) ) { - forcedAccessType = AccessType.FIELD; - - } - else { - context.logMessage( Diagnostic.Kind.ERROR, "Unexpected type for access type" ); - } - } - } - return forcedAccessType; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); - sb.append( "MetaEntity" ); + sb.append( "AnnotationMetaEntity" ); sb.append( "{element=" ).append( element ); + sb.append( ", members=" ).append( members ); sb.append( '}' ); return sb.toString(); } - class TypeVisitor extends SimpleTypeVisitor6 { - - AnnotationMetaEntity parent; - - /* - * If {@code explicitAccessType == null}, process all members as implicit. If {@code explicitAccessType != null} - * only process members marked as {@code @Access(explicitAccessType)}. - */ - private AccessType explicitAccessType; - - TypeVisitor(AnnotationMetaEntity parent, AccessType explicitAccessType) { - this.parent = parent; - this.explicitAccessType = explicitAccessType; - } - - @Override - protected AnnotationMetaAttribute defaultAction(TypeMirror e, Element p) { - return super.defaultAction( e, p ); - } - - @Override - public AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) { - if ( isPersistent( element ) ) { - return new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) ); - } - else { - return null; - } - } - - @Override - public AnnotationMetaAttribute visitArray(ArrayType t, Element element) { - if ( isPersistent( element ) ) { - return new AnnotationMetaSingleAttribute( parent, element, TypeUtils.toTypeString( t ) ); - } - else { - return null; - } - } - - private boolean isPersistent(Element element) { - //FIXME consider XML - boolean correctAccessType = false; - if ( this.explicitAccessType == null ) { - correctAccessType = true; - } - else { - AccessType annotationAccessType = determineAnnotationSpecifiedAccessType( element ); - if ( explicitAccessType.equals( annotationAccessType ) ) { - correctAccessType = true; - } - } - return correctAccessType - && !TypeUtils.containsAnnotation( element, Transient.class ) - && !element.getModifiers().contains( Modifier.TRANSIENT ) - && !element.getModifiers().contains( Modifier.STATIC ); - - } - - @Override - public AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) { - if ( isPersistent( element ) ) { - TypeElement returnedElement = ( TypeElement ) context.getProcessingEnvironment() - .getTypeUtils() - .asElement( declaredType ); - // WARNING: .toString() is necessary here since Name equals does not compare to String - String fqNameOfReturnType = returnedElement.getQualifiedName().toString(); - String collection = COLLECTIONS.get( fqNameOfReturnType ); - String targetEntity = getTargetEntity( element.getAnnotationMirrors() ); - if ( collection != null ) { - if ( TypeUtils.containsAnnotation( element, ElementCollection.class ) ) { - String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() ); - TypeMirror collectionElementType = getCollectionElementType( - declaredType, fqNameOfReturnType, explicitTargetEntity - ); - final TypeElement collectionElement = ( TypeElement ) context.getProcessingEnvironment() - .getTypeUtils() - .asElement( collectionElementType ); - this.parent.context.processElement( - collectionElement, - this.parent.defaultAccessTypeForElement - ); - } - if ( collection.equals( "javax.persistence.metamodel.MapAttribute" ) ) { - return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity ); - } - else { - return new AnnotationMetaCollection( - parent, element, collection, getElementType( declaredType, targetEntity ) - ); - } - } - else { - //FIXME Consider XML - if ( TypeUtils.containsAnnotation( returnedElement, Embedded.class, Embeddable.class ) ) { - this.parent.context.processElement( - returnedElement, - this.parent.defaultAccessTypeForElement - ); - } - return new AnnotationMetaSingleAttribute( - parent, element, returnedElement.getQualifiedName().toString() - ); - } - } - else { - return null; - } - } - - 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 - ), DEFAULT_ANNOTATION_PARAMETER_NAME - ); - keyType = typeMirror.toString(); - } - else { - keyType = getKeyType( declaredType ); - } - return new AnnotationMetaMap( - parent, - element, - collection, - keyType, - getElementType( declaredType, targetEntity ) - ); - } - - private TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, String explicitTargetEntityName) { - TypeMirror collectionElementType; - if ( explicitTargetEntityName != null ) { - Elements elements = context.getProcessingEnvironment().getElementUtils(); - TypeElement element = elements.getTypeElement( explicitTargetEntityName ); - collectionElementType = element.asType(); - } - else { - List typeArguments = t.getTypeArguments(); - if ( typeArguments.size() == 0 ) { - throw new MetaModelGenerationException( "Unable to determine collection type for property in " + getSimpleName() ); - } - else if ( Map.class.getCanonicalName().equals( fqNameOfReturnedType ) ) { - collectionElementType = t.getTypeArguments().get( 1 ); - } - else { - collectionElementType = t.getTypeArguments().get( 0 ); - } - } - return collectionElementType; - } - - @Override - public AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) { - if ( !p.getKind().equals( ElementKind.METHOD ) ) { - return null; + private void addPersistentMembers(List membersOfClass, AccessType membersKind) { + for ( Element memberOfClass : membersOfClass ) { + AccessType forcedAccessType = TypeUtils.determineAnnotationSpecifiedAccessType( memberOfClass ); + if ( entityAccessTypeInfo.getAccessType() != membersKind && forcedAccessType == null ) { + continue; } - String string = p.getSimpleName().toString(); - if ( string.startsWith( "get" ) || string.startsWith( "is" ) || string.startsWith( "has" ) ) { - TypeMirror returnType = t.getReturnType(); - return returnType.accept( this, p ); + if ( TypeUtils.containsAnnotation( memberOfClass, Transient.class ) + || memberOfClass.getModifiers().contains( Modifier.TRANSIENT ) + || memberOfClass.getModifiers().contains( Modifier.STATIC ) ) { + continue; } - else { - return null; + + TypeVisitor visitor = new TypeVisitor( this ); + AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass ); + if ( result != null ) { + members.put( result.getPropertyName(), result ); } } } - /** - * @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 annotations) { + protected void init() { + TypeUtils.determineAccessTypeForHierarchy( element, context ); + entityAccessTypeInfo = context.getAccessTypeInfo( getQualifiedName() ); - 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" ); - } - } - return fullyQualifiedTargetEntityName; - } + List fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() ); + addPersistentMembers( fieldsOfClass, AccessType.FIELD ); - 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; + List methodsOfClass = ElementFilter.methodsIn( element.getEnclosedElements() ); + addPersistentMembers( methodsOfClass, AccessType.PROPERTY ); } public String generateImports() { @@ -539,29 +181,253 @@ public class AnnotationMetaEntity implements MetaEntity { return element; } - private String getKeyType(DeclaredType t) { - return TypeUtils.extractClosestRealTypeAsString( t.getTypeArguments().get( 0 ), context ); + class TypeVisitor extends SimpleTypeVisitor6 { + 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 ) ); + } + + @Override + public AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) { + 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 + ); + 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 ) + ); + } + } + else { + if ( isBasicAttribute( element, returnedElement ) ) { + return new AnnotationMetaSingleAttribute( + parent, element, returnedElement.getQualifiedName().toString() + ); + } + else { + return null; + } + } + } + + @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 = getKeyType( declaredType ); + } + return new AnnotationMetaMap( + parent, + element, + collection, + keyType, + getElementType( declaredType, targetEntity ) + ); + } + + private String getElementType(DeclaredType declaredType, String targetEntity) { + if ( targetEntity != null ) { + return targetEntity; + } + final List 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 "?"; + } + } + + private String getKeyType(DeclaredType t) { + List typeArguments = t.getTypeArguments(); + if ( typeArguments.size() == 0 ) { + context.logMessage( Diagnostic.Kind.ERROR, "Entity: " + getQualifiedName() ); + } + return TypeUtils.extractClosestRealTypeAsString( typeArguments.get( 0 ), context ); + } + + /** + * @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 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" ); + } + } + 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; + } } - private String getElementType(DeclaredType declaredType, String targetEntity) { - if ( targetEntity != null ) { - return targetEntity; + /** + * 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 { + @Override + public Boolean visitPrimitive(PrimitiveType t, Element element) { + return Boolean.TRUE; } - final List mirrors = declaredType.getTypeArguments(); - if ( mirrors.size() == 1 ) { - final TypeMirror type = mirrors.get( 0 ); - return TypeUtils.extractClosestRealTypeAsString( type, context ); + + @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() ); } - 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 ); + + @Override + public Boolean visitDeclared(DeclaredType declaredType, Element element) { + if ( ElementKind.ENUM.equals( element.getKind() ) ) { + return Boolean.TRUE; } - return "?"; + + if ( ElementKind.CLASS.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; } } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaSingleAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaSingleAttribute.java index 05937939b3..6376bff6a8 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaSingleAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/AnnotationMetaSingleAttribute.java @@ -19,7 +19,7 @@ package org.hibernate.jpamodelgen.annotation; import javax.lang.model.element.Element; -import org.hibernate.jpamodelgen.MetaSingleAttribute; +import org.hibernate.jpamodelgen.model.MetaSingleAttribute; /** * @author Max Andersen diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContext.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/ImportContext.java similarity index 94% rename from tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContext.java rename to tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/ImportContext.java index a9c2b6fd48..151f64d2b4 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ImportContext.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/ImportContext.java @@ -15,10 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.hibernate.jpamodelgen; +package org.hibernate.jpamodelgen.model; /** - * * @author Max Andersen * @author Hardy Ferentschik * @author Emmanuel Bernard diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaAttribute.java similarity index 95% rename from tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaAttribute.java rename to tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaAttribute.java index 4ae7cf4b66..fc072f7fb9 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaAttribute.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.hibernate.jpamodelgen; +package org.hibernate.jpamodelgen.model; /** * @author Hardy Ferentschik diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaCollection.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaCollection.java similarity index 95% rename from tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaCollection.java rename to tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaCollection.java index 1e592c6f71..64df6447b9 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaCollection.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaCollection.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.hibernate.jpamodelgen; +package org.hibernate.jpamodelgen.model; /** * @author Hardy Ferentschik diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaEntity.java similarity index 75% rename from tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaEntity.java rename to tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaEntity.java index 7b42c9e118..f30ad4da26 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaEntity.java @@ -15,31 +15,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.hibernate.jpamodelgen; +package org.hibernate.jpamodelgen.model; +import java.util.List; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; -import java.util.List; /** * @author Hardy Ferentschik */ public interface MetaEntity extends ImportContext { - String getSimpleName(); + String getSimpleName(); - String getQualifiedName(); + String getQualifiedName(); - String getPackageName(); + String getPackageName(); - List getMembers(); + List getMembers(); - String generateImports(); + String generateImports(); - String importType(String fqcn); + String importType(String fqcn); - String staticImport(String fqcn, String member); + String staticImport(String fqcn, String member); - String importType(Name qualifiedName); + String importType(Name qualifiedName); TypeElement getTypeElement(); + + boolean isMetaComplete(); } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaSingleAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaSingleAttribute.java similarity index 95% rename from tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaSingleAttribute.java rename to tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaSingleAttribute.java index 36e960e712..69107aee8d 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/MetaSingleAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/model/MetaSingleAttribute.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.hibernate.jpamodelgen; +package org.hibernate.jpamodelgen.model; /** * @author Hardy Ferentschik diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java new file mode 100644 index 0000000000..e792b7e2a4 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/Constants.java @@ -0,0 +1,69 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Hardy Ferentschik + */ +public class Constants { + public static Map COLLECTIONS = new HashMap(); + + static { + COLLECTIONS.put( "java.util.Collection", "javax.persistence.metamodel.CollectionAttribute" ); + COLLECTIONS.put( "java.util.Set", "javax.persistence.metamodel.SetAttribute" ); + COLLECTIONS.put( "java.util.List", "javax.persistence.metamodel.ListAttribute" ); + COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" ); + } + + public static List BASIC_TYPES = new ArrayList(); + + static { + BASIC_TYPES.add( "java.lang.String" ); + BASIC_TYPES.add( "java.lang.Boolean" ); + BASIC_TYPES.add( "java.lang.Byte" ); + BASIC_TYPES.add( "java.lang.Character" ); + BASIC_TYPES.add( "java.lang.Short" ); + BASIC_TYPES.add( "java.lang.Integer" ); + BASIC_TYPES.add( "java.lang.Long" ); + BASIC_TYPES.add( "java.lang.Float" ); + BASIC_TYPES.add( "java.lang.Double" ); + BASIC_TYPES.add( "java.math.BigInteger" ); + BASIC_TYPES.add( "java.math.BigDecimal" ); + BASIC_TYPES.add( "java.util.Date" ); + BASIC_TYPES.add( "java.util.Calendar" ); + BASIC_TYPES.add( "java.sql.Date" ); + BASIC_TYPES.add( "java.sql.Time" ); + BASIC_TYPES.add( "java.sql.Timestamp" ); + } + + public static List BASIC_ARRAY_TYPES = new ArrayList(); + + static { + BASIC_ARRAY_TYPES.add( "java.lang.Character" ); + BASIC_ARRAY_TYPES.add( "java.lang.Byte" ); + } + + private Constants(){} +} + + diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/StringUtil.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/StringUtil.java new file mode 100644 index 0000000000..02480c99f8 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/StringUtil.java @@ -0,0 +1,77 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.util; + +/** + * @author Hardy Ferentschik + */ +public class StringUtil { + private static final String NAME_SEPARATOR = "."; + private static final String PROPERTY_PREFIX_GET = "get"; + private static final String PROPERTY_PREFIX_IS = "is"; + private static final String PROPERTY_PREFIX_HAS = "has"; + + private StringUtil() { + } + + public static String determineFullyQualifiedClassName(String packageName, String name) { + if ( isFullyQualified( name ) ) { + return name; + } + else { + return packageName + NAME_SEPARATOR + name; + } + } + + public static boolean isFullyQualified(String name) { + return name.contains( NAME_SEPARATOR ); + } + + public static String packageNameFromFqcn(String fqcn) { + return fqcn.substring( 0, fqcn.lastIndexOf( NAME_SEPARATOR ) ); + } + + public static String classNameFromFqcn(String fqcn) { + return fqcn.substring( fqcn.lastIndexOf( NAME_SEPARATOR ) + 1 ); + } + + public static boolean isPropertyName(String name) { + return name.startsWith( PROPERTY_PREFIX_GET ) || name.startsWith( PROPERTY_PREFIX_IS ) || name.startsWith( + PROPERTY_PREFIX_HAS + ); + } + + public static String getPropertyName(String name) { + if ( !isPropertyName( name ) ) { + return null; + } + + if ( name.startsWith( PROPERTY_PREFIX_GET ) ) { + name = name.replaceFirst( PROPERTY_PREFIX_GET, "" ); + } + else if ( name.startsWith( PROPERTY_PREFIX_IS ) ) { + name = name.replaceFirst( PROPERTY_PREFIX_IS, "" ); + } + else if ( name.startsWith( PROPERTY_PREFIX_HAS ) ) { + name = name.replaceFirst( PROPERTY_PREFIX_HAS, "" ); + } + return name.substring(0,1).toLowerCase() + name.substring(1); + } +} + + diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java index 066c004e31..6111bcce36 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java @@ -25,15 +25,30 @@ 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.TypeElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; 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.Elements; +import javax.lang.model.util.SimpleTypeVisitor6; import javax.lang.model.util.Types; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Embeddable; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.tools.Diagnostic; +import org.hibernate.jpamodelgen.AccessTypeInformation; import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.MetaModelGenerationException; /** * Utility class. @@ -44,6 +59,7 @@ import org.hibernate.jpamodelgen.Context; */ public class TypeUtils { + public static final String DEFAULT_ANNOTATION_PARAMETER_NAME = "value"; private static final Map PRIMITIVES = new HashMap(); static { @@ -84,7 +100,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.getTypeUtils(); final List upperBounds = types.directSupertypes( compositeUpperBound ); if ( upperBounds.size() == 0 ) { return compositeUpperBound.toString(); @@ -181,4 +197,220 @@ public class TypeUtils { } return returnValue; } + + public static void determineAccessTypeForHierarchy(TypeElement searchedElement, Context context) { + String fqcn = searchedElement.getQualifiedName().toString(); + context.logMessage( Diagnostic.Kind.OTHER, "Determining access type for " + fqcn ); + AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn ); + + if ( accessTypeInfo != null && accessTypeInfo.isAccessTypeResolved() ) { + context.logMessage( + Diagnostic.Kind.OTHER, + "AccessType for " + searchedElement.toString() + "found in cache: " + accessTypeInfo + ); + return; + } + + // check for explicit access type + AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( searchedElement ); + if ( forcedAccessType != null ) { + context.logMessage( + Diagnostic.Kind.OTHER, "Explicit access type on " + searchedElement + ":" + forcedAccessType + ); + accessTypeInfo = new AccessTypeInformation( fqcn, forcedAccessType, null ); + context.addAccessTypeInformation( fqcn, accessTypeInfo ); + updateEmbeddableAccessType( searchedElement, context, forcedAccessType ); + return; + } + + // need to find the default access type for this class + // let's check first if this entity is the root of the class hierarchy and defines an id. If so the + // placement of the id annotation determines the access type + AccessType defaultAccessType = getAccessTypeInCaseElementIsRoot( searchedElement, context ); + if ( defaultAccessType != null ) { + accessTypeInfo = new AccessTypeInformation( fqcn, null, defaultAccessType ); + context.addAccessTypeInformation( fqcn, accessTypeInfo ); + updateEmbeddableAccessType( searchedElement, context, defaultAccessType ); + return; + } + + // if we end up here we need to recursively look for superclasses + defaultAccessType = getDefaultAccessForHierarchy( searchedElement, context ); + if ( defaultAccessType == null ) { + defaultAccessType = AccessType.PROPERTY; + } + accessTypeInfo = new AccessTypeInformation( fqcn, null, defaultAccessType ); + context.addAccessTypeInformation( fqcn, accessTypeInfo ); + } + + public static TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, String explicitTargetEntityName, Context context) { + TypeMirror collectionElementType; + if ( explicitTargetEntityName != null ) { + Elements elements = context.getElementUtils(); + TypeElement element = elements.getTypeElement( explicitTargetEntityName ); + collectionElementType = element.asType(); + } + else { + List typeArguments = t.getTypeArguments(); + if ( typeArguments.size() == 0 ) { + throw new MetaModelGenerationException( "Unable to determine collection type" ); + } + else if ( Map.class.getCanonicalName().equals( fqNameOfReturnedType ) ) { + collectionElementType = t.getTypeArguments().get( 1 ); + } + else { + collectionElementType = t.getTypeArguments().get( 0 ); + } + } + return collectionElementType; + } + + private static void updateEmbeddableAccessType(TypeElement element, Context context, AccessType defaultAccessType) { + List fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() ); + for ( Element field : fieldsOfClass ) { + updateEmbeddableAccessTypeForMember( context, defaultAccessType, field ); + } + + List methodOfClass = ElementFilter.methodsIn( element.getEnclosedElements() ); + for ( Element method : methodOfClass ) { + updateEmbeddableAccessTypeForMember( context, defaultAccessType, method ); + } + } + + private static void updateEmbeddableAccessTypeForMember(Context context, AccessType defaultAccessType, Element member) { + EmbeddedAttributeVisitor visitor = new EmbeddedAttributeVisitor( context ); + String embeddedClassName = member.asType().accept( visitor, member ); + if ( embeddedClassName != null ) { + AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( embeddedClassName ); + if ( accessTypeInfo == null ) { + accessTypeInfo = new AccessTypeInformation( embeddedClassName, null, defaultAccessType ); + context.addAccessTypeInformation( embeddedClassName, accessTypeInfo ); + } + else { + accessTypeInfo.setDefaultAccessType( defaultAccessType ); + } + } + } + + private static AccessType getDefaultAccessForHierarchy(TypeElement element, Context context) { + AccessType defaultAccessType = null; + TypeElement superClass = element; + do { + superClass = TypeUtils.getSuperclassTypeElement( superClass ); + if ( superClass != null ) { + String fqcn = superClass.getQualifiedName().toString(); + AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn ); + if ( accessTypeInfo != null && accessTypeInfo.getDefaultAccessType() != null ) { + return accessTypeInfo.getDefaultAccessType(); + } + if ( TypeUtils.containsAnnotation( superClass, Entity.class, MappedSuperclass.class ) ) { + defaultAccessType = getAccessTypeInCaseElementIsRoot( superClass, context ); + if ( defaultAccessType != null ) { + accessTypeInfo = new AccessTypeInformation( fqcn, null, defaultAccessType ); + context.addAccessTypeInformation( fqcn, accessTypeInfo ); + defaultAccessType = accessTypeInfo.getAccessType(); + } + else { + defaultAccessType = getDefaultAccessForHierarchy( superClass, context ); + } + } + } + } + while ( superClass != null ); + return defaultAccessType; + } + + private static AccessType getAccessTypeInCaseElementIsRoot(TypeElement searchedElement, Context context) { + AccessType defaultAccessType = null; + List myMembers = searchedElement.getEnclosedElements(); + for ( Element subElement : myMembers ) { + List entityAnnotations = + context.getElementUtils().getAllAnnotationMirrors( subElement ); + for ( Object entityAnnotation : entityAnnotations ) { + AnnotationMirror annotationMirror = ( AnnotationMirror ) entityAnnotation; + if ( isIdAnnotation( annotationMirror ) ) { + defaultAccessType = getAccessTypeOfIdAnnotation( subElement ); + break; + } + } + } + return defaultAccessType; + } + + private static AccessType getAccessTypeOfIdAnnotation(Element element) { + AccessType accessType = null; + final ElementKind kind = element.getKind(); + if ( kind == ElementKind.FIELD || kind == ElementKind.METHOD ) { + accessType = kind == ElementKind.FIELD ? AccessType.FIELD : AccessType.PROPERTY; + } + return accessType; + } + + private static boolean isIdAnnotation(AnnotationMirror annotationMirror) { + return TypeUtils.isAnnotationMirrorOfType( annotationMirror, Id.class ) + || TypeUtils.isAnnotationMirrorOfType( annotationMirror, EmbeddedId.class ); + } + + public static AccessType determineAnnotationSpecifiedAccessType(Element element) { + final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Access.class ); + AccessType forcedAccessType = null; + if ( accessAnnotationMirror != null ) { + Element accessElement = ( Element ) TypeUtils.getAnnotationValue( + accessAnnotationMirror, + DEFAULT_ANNOTATION_PARAMETER_NAME + ); + if ( accessElement.getKind().equals( ElementKind.ENUM_CONSTANT ) ) { + if ( accessElement.getSimpleName().toString().equals( AccessType.PROPERTY.toString() ) ) { + forcedAccessType = AccessType.PROPERTY; + } + else if ( accessElement.getSimpleName().toString().equals( AccessType.FIELD.toString() ) ) { + forcedAccessType = AccessType.FIELD; + } + } + } + return forcedAccessType; + } + + public static ElementKind getElementKindForAccessType(AccessType accessType) { + if ( AccessType.FIELD.equals( accessType ) ) { + return ElementKind.FIELD; + } + else { + return ElementKind.METHOD; + } + } + + static class EmbeddedAttributeVisitor extends SimpleTypeVisitor6 { + + private Context context; + + EmbeddedAttributeVisitor(Context context) { + this.context = context; + } + + @Override + public String visitDeclared(DeclaredType declaredType, Element element) { + TypeElement returnedElement = ( TypeElement ) context.getTypeUtils().asElement( declaredType ); + String fqNameOfReturnType = null; + if ( containsAnnotation( returnedElement, Embeddable.class ) ) { + fqNameOfReturnType = returnedElement.getQualifiedName().toString(); + } + return fqNameOfReturnType; + } + + @Override + public String 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 ); + } + } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaAttribute.java index 14dbded3a0..7d78b52742 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaAttribute.java @@ -18,7 +18,7 @@ package org.hibernate.jpamodelgen.xml; -import org.hibernate.jpamodelgen.MetaAttribute; +import org.hibernate.jpamodelgen.model.MetaAttribute; /** * @author Hardy Ferentschik @@ -37,7 +37,6 @@ public abstract class XmlMetaAttribute implements MetaAttribute { this.type = type; } - @Override public String getDeclarationString() { return "public static volatile " + parentEntity.importType(getMetaType()) + "<" + parentEntity.importType(parentEntity.getQualifiedName()) + ", " + parentEntity.importType(getTypeDeclaration()) + "> " + getPropertyName() + ";"; @@ -53,4 +52,14 @@ public abstract class XmlMetaAttribute implements MetaAttribute { @Override abstract public String getMetaType(); + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "XmlMetaAttribute" ); + sb.append( "{propertyName='" ).append( propertyName ).append( '\'' ); + sb.append( ", type='" ).append( type ).append( '\'' ); + sb.append( '}' ); + return sb.toString(); + } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaCollection.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaCollection.java index e7a55d637a..f34b39c825 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaCollection.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaCollection.java @@ -17,7 +17,7 @@ */ package org.hibernate.jpamodelgen.xml; -import org.hibernate.jpamodelgen.MetaCollection; +import org.hibernate.jpamodelgen.model.MetaCollection; /** * @author Hardy Ferentschik diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java new file mode 100644 index 0000000000..52f66f0661 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEmbeddable.java @@ -0,0 +1,69 @@ +// $Id: XmlMetaEntity.java 18753 2010-02-09 21:29:34Z 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.xml; + +import java.util.List; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; + +import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.model.MetaAttribute; +import org.hibernate.jpamodelgen.xml.jaxb.Embeddable; + +/** + * @author Hardy Ferentschik + */ +public class XmlMetaEmbeddable extends XmlMetaEntity { + // Embeddables needs to be lazily initialized since the access type be determined by the class which is embedding + // the entity. This might not be known until annotations are processed. + // Also note, that if two different classes with different access types embed this entity the access type of the + // embeddable will be the one of the last embedding entity processed. The result is not determined (that's ok + // according to the spec) + private boolean initialized; + + public XmlMetaEmbeddable(Embeddable embeddable, String packageName, TypeElement element, Context context) { + super( embeddable, packageName, element, context ); + } + + public List getMembers() { + if ( !initialized ) { + context.logMessage( Diagnostic.Kind.OTHER, "Entity " + getQualifiedName() + "was lazily initialised." ); + init(); + initialized = true; + } + return members; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "XmlMetaEmbeddable" ); + sb.append( "{accessTypeInfo=" ).append( accessTypeInfo ); + sb.append( ", clazzName='" ).append( clazzName ).append( '\'' ); + sb.append( ", members=" ); + if ( initialized ) { + sb.append( members ); + } + else { + sb.append( "[un-initalized]" ); + } + sb.append( ", isMetaComplete=" ).append( isMetaComplete ); + sb.append( '}' ); + return sb.toString(); + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java index 923aa1c3f1..c83b4d3bbf 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java @@ -22,18 +22,22 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; +import org.hibernate.jpamodelgen.AccessTypeInformation; import org.hibernate.jpamodelgen.Context; -import org.hibernate.jpamodelgen.ImportContext; import org.hibernate.jpamodelgen.ImportContextImpl; -import org.hibernate.jpamodelgen.MetaAttribute; -import org.hibernate.jpamodelgen.MetaEntity; import org.hibernate.jpamodelgen.MetaModelGenerationException; +import org.hibernate.jpamodelgen.model.ImportContext; +import org.hibernate.jpamodelgen.model.MetaAttribute; +import org.hibernate.jpamodelgen.model.MetaEntity; +import org.hibernate.jpamodelgen.util.StringUtil; import org.hibernate.jpamodelgen.util.TypeUtils; import org.hibernate.jpamodelgen.xml.jaxb.Attributes; import org.hibernate.jpamodelgen.xml.jaxb.Basic; @@ -62,46 +66,61 @@ public class XmlMetaEntity implements MetaEntity { COLLECTIONS.put( "java.util.Map", "javax.persistence.metamodel.MapAttribute" ); } - final private String clazzName; + protected final String clazzName; + protected final String packageName; + protected final ImportContext importContext; + protected final List members = new ArrayList(); + protected final TypeElement element; + protected final Context context; + protected final boolean isMetaComplete; - final private String packageName; - - final private ImportContext importContext; - - final private List members = new ArrayList(); - - private TypeElement element; - private Context context; + private Attributes attributes; + private EmbeddableAttributes embeddableAttributes; + protected AccessTypeInformation accessTypeInfo; public XmlMetaEntity(Entity ormEntity, String packageName, TypeElement element, Context context) { - this.clazzName = ormEntity.getClazz(); - this.packageName = packageName; - this.context = context; - this.importContext = new ImportContextImpl( getPackageName() ); - this.element = element; - Attributes attributes = ormEntity.getAttributes(); - - parseAttributes( attributes ); + this( ormEntity.getClazz(), packageName, element, context, ormEntity.isMetadataComplete() ); + this.attributes = ormEntity.getAttributes(); + this.embeddableAttributes = null; + // entities can be directly initialised + init(); } - public XmlMetaEntity(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) { - this.clazzName = mappedSuperclass.getClazz(); - this.packageName = packageName; - this.context = context; - this.importContext = new ImportContextImpl( getPackageName() ); - this.element = element; - Attributes attributes = mappedSuperclass.getAttributes(); - parseAttributes( attributes ); + protected XmlMetaEntity(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) { + this( mappedSuperclass.getClazz(), packageName, element, context, mappedSuperclass.isMetadataComplete() ); + this.attributes = mappedSuperclass.getAttributes(); + this.embeddableAttributes = null; } - public XmlMetaEntity(Embeddable embeddable, String packageName, TypeElement element, Context context) { - this.clazzName = embeddable.getClazz(); + protected XmlMetaEntity(Embeddable embeddable, String packageName, TypeElement element, Context context) { + this( embeddable.getClazz(), packageName, element, context, embeddable.isMetadataComplete() ); + this.attributes = null; + this.embeddableAttributes = embeddable.getAttributes(); + } + + private XmlMetaEntity(String clazz, String packageName, TypeElement element, Context context, Boolean metaComplete) { + String className = clazz; + if ( StringUtil.isFullyQualified( className ) ) { + // we have to extract the package name from the fqcn. default package name gets ignored + packageName = StringUtil.packageNameFromFqcn( className ); + className = StringUtil.classNameFromFqcn( clazz ); + } + this.clazzName = className; this.packageName = packageName; this.context = context; this.importContext = new ImportContextImpl( getPackageName() ); this.element = element; - EmbeddableAttributes attributes = embeddable.getAttributes(); - parseEmbeddableAttributes( attributes ); + this.isMetaComplete = initIsMetaComplete( metaComplete ); + } + + protected void init() { + this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() ); + if ( attributes != null ) { + parseAttributes( attributes ); + } + else { + parseEmbeddableAttributes( embeddableAttributes ); + } } public String getSimpleName() { @@ -140,150 +159,295 @@ public class XmlMetaEntity implements MetaEntity { return element; } - private String[] getCollectionType(String propertyName, String explicitTargetEntity) { - String types[] = new String[2]; - for ( Element elem : element.getEnclosedElements() ) { - if ( elem.getSimpleName().toString().equals( propertyName ) ) { - DeclaredType type = ( ( DeclaredType ) elem.asType() ); - List typeArguments = type.getTypeArguments(); - - if ( typeArguments.size() == 0 && explicitTargetEntity == null ) { - throw new MetaModelGenerationException( "Unable to determine target entity type for " + clazzName + "." + propertyName + "." ); - } - - if ( explicitTargetEntity == null ) { - types[0] = TypeUtils.extractClosestRealTypeAsString( typeArguments.get( 0 ), context ); - } - else { - types[0] = explicitTargetEntity; - } - types[1] = COLLECTIONS.get( type.asElement().toString() ); - } - } - return types; - } - - /** - * Returns the entity type for relation. - * - * @param propertyName The property name of the association - * @param explicitTargetEntity The explicitly specified target entity type - * - * @return The entity type for relation/association. - */ - private String getType(String propertyName, String explicitTargetEntity) { - if ( explicitTargetEntity != null ) { - // TODO should there be a check of the target entity class and if it is loadable? - return explicitTargetEntity; - } - - String typeName = null; - for ( Element elem : element.getEnclosedElements() ) { - if ( elem.getSimpleName().toString().equals( propertyName ) ) { - switch ( elem.asType().getKind() ) { - case INT: { - typeName = "java.lang.Integer"; - break; - } - case LONG: { - typeName = "java.lang.Long"; - break; - } - case BOOLEAN: { - typeName = "java.lang.Boolean"; - break; - } - case DECLARED: { - typeName = elem.asType().toString(); - break; - } - case TYPEVAR: { - typeName = elem.asType().toString(); - break; - } - } - break; - } - } - return typeName; + @Override + public boolean isMetaComplete() { + return isMetaComplete; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append( "XmlMetaEntity" ); - sb.append( "{type=" ).append( element ); + sb.append( "{accessTypeInfo=" ).append( accessTypeInfo ); + sb.append( ", clazzName='" ).append( clazzName ).append( '\'' ); + sb.append( ", members=" ).append( members ); + sb.append( ", isMetaComplete=" ).append( isMetaComplete ); sb.append( '}' ); return sb.toString(); } + private boolean initIsMetaComplete(Boolean metadataComplete) { + return context.isPersistenceUnitCompletelyXmlConfigured() || Boolean.TRUE.equals( metadataComplete ); + } + + private String[] getCollectionType(String propertyName, String explicitTargetEntity, ElementKind expectedElementKind) { + String types[] = new String[2]; + for ( Element elem : element.getEnclosedElements() ) { + if ( expectedElementKind.equals( elem.getKind() ) ) { + continue; + } + + if ( !elem.getSimpleName().toString().equals( propertyName ) ) { + continue; + } + + DeclaredType type = ( ( DeclaredType ) elem.asType() ); + List typeArguments = type.getTypeArguments(); + + if ( typeArguments.size() == 0 && explicitTargetEntity == null ) { + throw new MetaModelGenerationException( "Unable to determine target entity type for " + clazzName + "." + propertyName + "." ); + } + + if ( explicitTargetEntity == null ) { + types[0] = TypeUtils.extractClosestRealTypeAsString( typeArguments.get( 0 ), context ); + } + else { + types[0] = explicitTargetEntity; + } + types[1] = COLLECTIONS.get( type.asElement().toString() ); + return types; + + } + return null; + } + + /** + * Returns the entity type for a property. + * + * @param propertyName The property name + * @param explicitTargetEntity The explicitly specified target entity type or {@code null}. + * @param expectedElementKind Determines property vs field access type + * + * @return The entity type for this property or {@code null} if the property with the name and the matching access + * type does not exist. + */ + private String getType(String propertyName, String explicitTargetEntity, ElementKind expectedElementKind) { + for ( Element elem : element.getEnclosedElements() ) { + if ( !expectedElementKind.equals( elem.getKind() ) ) { + continue; + } + + TypeMirror mirror; + String name = elem.getSimpleName().toString(); + if ( ElementKind.METHOD.equals( elem.getKind() ) ) { + name = StringUtil.getPropertyName( name ); + mirror = ( ( ExecutableElement ) elem ).getReturnType(); + } + else { + mirror = elem.asType(); + } + + if ( name == null || !name.equals( propertyName ) ) { + continue; + } + + if ( explicitTargetEntity != null ) { + // TODO should there be a check of the target entity class and if it is loadable? + return explicitTargetEntity; + } + + switch ( mirror.getKind() ) { + case INT: { + return "java.lang.Integer"; + } + case LONG: { + return "java.lang.Long"; + } + case BOOLEAN: { + return "java.lang.Boolean"; + } + case BYTE: { + return "java.lang.Byte"; + } + case SHORT: { + return "java.lang.Short"; + } + case CHAR: { + return "java.lang.Char"; + } + case FLOAT: { + return "java.lang.Float"; + } + case DOUBLE: { + return "java.lang.Double"; + } + case DECLARED: { + return mirror.toString(); + } + case TYPEVAR: { + return mirror.toString(); + } + } + } + + context.logMessage( + Diagnostic.Kind.WARNING, + "Unable to determine type for property " + propertyName + " of class " + getQualifiedName() + + " using assess type " + accessTypeInfo.getDefaultAccessType() + ); + return null; + } + private void parseAttributes(Attributes attributes) { XmlMetaSingleAttribute attribute; - - if ( !attributes.getId().isEmpty() ) { - // TODO what do we do if there are more than one id nodes? - Id id = attributes.getId().get( 0 ); - attribute = new XmlMetaSingleAttribute( - this, id.getName(), getType( id.getName(), null ) - ); - members.add( attribute ); + for ( Id id : attributes.getId() ) { + ElementKind elementKind = getElementKind( id.getAccess() ); + String type = getType( id.getName(), null, elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, id.getName(), type ); + members.add( attribute ); + } } for ( Basic basic : attributes.getBasic() ) { - attribute = new XmlMetaSingleAttribute( this, basic.getName(), getType( basic.getName(), null ) ); - members.add( attribute ); + ElementKind elementKind = getElementKind( basic.getAccess() ); + String type = getType( basic.getName(), null, elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, basic.getName(), type ); + members.add( attribute ); + } } for ( ManyToOne manyToOne : attributes.getManyToOne() ) { - attribute = new XmlMetaSingleAttribute( - this, manyToOne.getName(), getType( manyToOne.getName(), manyToOne.getTargetEntity() ) - ); - members.add( attribute ); + ElementKind elementKind = getElementKind( manyToOne.getAccess() ); + String type = getType( manyToOne.getName(), manyToOne.getTargetEntity(), elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, manyToOne.getName(), type ); + members.add( attribute ); + } } for ( OneToOne oneToOne : attributes.getOneToOne() ) { - attribute = new XmlMetaSingleAttribute( - this, oneToOne.getName(), getType( oneToOne.getName(), oneToOne.getTargetEntity() ) - ); - members.add( attribute ); + ElementKind elementKind = getElementKind( oneToOne.getAccess() ); + String type = getType( oneToOne.getName(), oneToOne.getTargetEntity(), elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, oneToOne.getName(), type ); + members.add( attribute ); + } } XmlMetaCollection metaCollection; String[] types; for ( ManyToMany manyToMany : attributes.getManyToMany() ) { + ElementKind elementKind = getElementKind( manyToMany.getAccess() ); try { - types = getCollectionType( manyToMany.getName(), manyToMany.getTargetEntity() ); + types = getCollectionType( manyToMany.getName(), manyToMany.getTargetEntity(), elementKind ); } catch ( MetaModelGenerationException e ) { logMetaModelException( manyToMany.getName(), e ); break; } - metaCollection = new XmlMetaCollection( this, manyToMany.getName(), types[0], types[1] ); - members.add( metaCollection ); + if ( types != null ) { + metaCollection = new XmlMetaCollection( this, manyToMany.getName(), types[0], types[1] ); + members.add( metaCollection ); + } } for ( OneToMany oneToMany : attributes.getOneToMany() ) { + ElementKind elementKind = getElementKind( oneToMany.getAccess() ); try { - types = getCollectionType( oneToMany.getName(), oneToMany.getTargetEntity() ); + types = getCollectionType( oneToMany.getName(), oneToMany.getTargetEntity(), elementKind ); } catch ( MetaModelGenerationException e ) { logMetaModelException( oneToMany.getName(), e ); break; } - metaCollection = new XmlMetaCollection( this, oneToMany.getName(), types[0], types[1] ); - members.add( metaCollection ); + if ( types != null ) { + metaCollection = new XmlMetaCollection( this, oneToMany.getName(), types[0], types[1] ); + members.add( metaCollection ); + } } for ( ElementCollection collection : attributes.getElementCollection() ) { + ElementKind elementKind = getElementKind( collection.getAccess() ); try { - types = getCollectionType( collection.getName(), collection.getTargetClass() ); + types = getCollectionType( collection.getName(), collection.getTargetClass(), elementKind ); } catch ( MetaModelGenerationException e ) { logMetaModelException( collection.getName(), e ); break; } - metaCollection = new XmlMetaCollection( this, collection.getName(), types[0], types[1] ); - members.add( metaCollection ); + if ( types != null ) { + metaCollection = new XmlMetaCollection( this, collection.getName(), types[0], types[1] ); + members.add( metaCollection ); + } + } + } + + private void parseEmbeddableAttributes(EmbeddableAttributes attributes) { + XmlMetaSingleAttribute attribute; + for ( Basic basic : attributes.getBasic() ) { + ElementKind elementKind = getElementKind( basic.getAccess() ); + String type = getType( basic.getName(), null, elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, basic.getName(), type ); + members.add( attribute ); + } + } + + for ( ManyToOne manyToOne : attributes.getManyToOne() ) { + ElementKind elementKind = getElementKind( manyToOne.getAccess() ); + String type = getType( manyToOne.getName(), manyToOne.getTargetEntity(), elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, manyToOne.getName(), type ); + members.add( attribute ); + } + } + + for ( OneToOne oneToOne : attributes.getOneToOne() ) { + ElementKind elementKind = getElementKind( oneToOne.getAccess() ); + String type = getType( oneToOne.getName(), oneToOne.getTargetEntity(), elementKind ); + if ( type != null ) { + attribute = new XmlMetaSingleAttribute( this, oneToOne.getName(), type ); + members.add( attribute ); + } + } + + XmlMetaCollection metaCollection; + String[] types; + for ( ManyToMany manyToMany : attributes.getManyToMany() ) { + ElementKind elementKind = getElementKind( manyToMany.getAccess() ); + try { + types = getCollectionType( manyToMany.getName(), manyToMany.getTargetEntity(), elementKind ); + } + catch ( MetaModelGenerationException e ) { + logMetaModelException( manyToMany.getName(), e ); + break; + } + if ( types != null ) { + metaCollection = new XmlMetaCollection( this, manyToMany.getName(), types[0], types[1] ); + members.add( metaCollection ); + } + } + + for ( OneToMany oneToMany : attributes.getOneToMany() ) { + ElementKind elementKind = getElementKind( oneToMany.getAccess() ); + try { + types = getCollectionType( oneToMany.getName(), oneToMany.getTargetEntity(), elementKind ); + } + catch ( MetaModelGenerationException e ) { + logMetaModelException( oneToMany.getName(), e ); + break; + } + if ( types != null ) { + metaCollection = new XmlMetaCollection( this, oneToMany.getName(), types[0], types[1] ); + members.add( metaCollection ); + } + } + + for ( ElementCollection collection : attributes.getElementCollection() ) { + ElementKind elementKind = getElementKind( collection.getAccess() ); + try { + types = getCollectionType( collection.getName(), collection.getTargetClass(), elementKind ); + } + catch ( MetaModelGenerationException e ) { + logMetaModelException( collection.getName(), e ); + break; + } + if ( types != null ) { + metaCollection = new XmlMetaCollection( this, collection.getName(), types[0], types[1] ); + members.add( metaCollection ); + } } } @@ -301,44 +465,17 @@ public class XmlMetaEntity implements MetaEntity { ); } - private void parseEmbeddableAttributes(EmbeddableAttributes attributes) { - XmlMetaSingleAttribute attribute; - for ( Basic basic : attributes.getBasic() ) { - attribute = new XmlMetaSingleAttribute( this, basic.getName(), getType( basic.getName(), null ) ); - members.add( attribute ); + private ElementKind getElementKind(org.hibernate.jpamodelgen.xml.jaxb.AccessType accessType) { + // if no explicit access type was specified in xml we use the entity access type + if ( accessType == null ) { + return TypeUtils.getElementKindForAccessType( accessTypeInfo.getDefaultAccessType() ); } - for ( ManyToOne manyToOne : attributes.getManyToOne() ) { - attribute = new XmlMetaSingleAttribute( - this, manyToOne.getName(), getType( manyToOne.getName(), manyToOne.getTargetEntity() ) - ); - members.add( attribute ); + if ( org.hibernate.jpamodelgen.xml.jaxb.AccessType.FIELD.equals( accessType ) ) { + return ElementKind.FIELD; } - - for ( OneToOne oneToOne : attributes.getOneToOne() ) { - attribute = new XmlMetaSingleAttribute( - this, oneToOne.getName(), getType( oneToOne.getName(), oneToOne.getTargetEntity() ) - ); - members.add( attribute ); - } - - XmlMetaCollection metaCollection; - for ( ManyToMany manyToMany : attributes.getManyToMany() ) { - String[] types = getCollectionType( manyToMany.getName(), manyToMany.getTargetEntity() ); - metaCollection = new XmlMetaCollection( this, manyToMany.getName(), types[0], types[1] ); - members.add( metaCollection ); - } - - for ( OneToMany oneToMany : attributes.getOneToMany() ) { - String[] types = getCollectionType( oneToMany.getName(), oneToMany.getTargetEntity() ); - metaCollection = new XmlMetaCollection( this, oneToMany.getName(), types[0], types[1] ); - members.add( metaCollection ); - } - - for ( ElementCollection collection : attributes.getElementCollection() ) { - String[] types = getCollectionType( collection.getName(), collection.getTargetClass() ); - metaCollection = new XmlMetaCollection( this, collection.getName(), types[0], types[1] ); - members.add( metaCollection ); + else { + return ElementKind.METHOD; } } } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java new file mode 100644 index 0000000000..4e599801c9 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaMappedSuperClass.java @@ -0,0 +1,74 @@ +// $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.xml; + +import java.util.List; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; + +import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.MetaModelGenerationException; +import org.hibernate.jpamodelgen.model.MetaAttribute; +import org.hibernate.jpamodelgen.xml.jaxb.Basic; +import org.hibernate.jpamodelgen.xml.jaxb.ElementCollection; +import org.hibernate.jpamodelgen.xml.jaxb.EmbeddableAttributes; +import org.hibernate.jpamodelgen.xml.jaxb.ManyToMany; +import org.hibernate.jpamodelgen.xml.jaxb.ManyToOne; +import org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass; +import org.hibernate.jpamodelgen.xml.jaxb.OneToMany; +import org.hibernate.jpamodelgen.xml.jaxb.OneToOne; + +/** + * @author Hardy Ferentschik + */ +public class XmlMetaMappedSuperClass extends XmlMetaEntity { + private boolean initialized; + + public XmlMetaMappedSuperClass(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) { + super( mappedSuperclass, packageName, element, context ); + } + + public List getMembers() { + if ( !initialized ) { + context.logMessage( Diagnostic.Kind.OTHER, "Entity " + getQualifiedName() + "was lazily initialised." ); + init(); + initialized = true; + } + return members; + } + + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append( "XmlMetaEntity" ); + sb.append( "{accessTypeInfo=" ).append( accessTypeInfo ); + sb.append( ", clazzName='" ).append( clazzName ).append( '\'' ); + sb.append( ", members=" ); + if ( initialized ) { + sb.append( members ); + } + else { + sb.append( "[un-initalized]" ); + } + sb.append( ", isMetaComplete=" ).append( isMetaComplete ); + sb.append( '}' ); + return sb.toString(); + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaSingleAttribute.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaSingleAttribute.java index 231dd715f0..ecc418eb1b 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaSingleAttribute.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaSingleAttribute.java @@ -17,7 +17,7 @@ */ package org.hibernate.jpamodelgen.xml; -import org.hibernate.jpamodelgen.MetaSingleAttribute; +import org.hibernate.jpamodelgen.model.MetaSingleAttribute; /** * @author Hardy Ferentschik diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java index be24bbf169..179632b6b8 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java @@ -20,6 +20,7 @@ package org.hibernate.jpamodelgen.xml; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.lang.model.element.TypeElement; @@ -36,7 +37,10 @@ import javax.xml.validation.SchemaFactory; import org.xml.sax.SAXException; +import org.hibernate.jpamodelgen.AccessTypeInformation; import org.hibernate.jpamodelgen.Context; +import org.hibernate.jpamodelgen.util.StringUtil; +import org.hibernate.jpamodelgen.util.TypeUtils; import org.hibernate.jpamodelgen.xml.jaxb.Entity; import org.hibernate.jpamodelgen.xml.jaxb.EntityMappings; import org.hibernate.jpamodelgen.xml.jaxb.ObjectFactory; @@ -48,132 +52,145 @@ import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitMetadata; * @author Hardy Ferentschik */ public class XmlParser { - - private static final String PERSISTENCE_XML = "/META-INF/persistence.xml"; private static final String ORM_XML = "/META-INF/orm.xml"; private static final String PERSISTENCE_XML_XSD = "persistence_2_0.xsd"; private static final String ORM_XSD = "orm_2_0.xsd"; private static final String PATH_SEPARATOR = "/"; - private static final AccessType DEFAULT_XML_ACCESS_TYPE = AccessType.PROPERTY; private Context context; + private List entityMappings; public XmlParser(Context context) { this.context = context; + this.entityMappings = new ArrayList(); } - public void parsePersistenceXml() { - Persistence persistence = parseXml( PERSISTENCE_XML, Persistence.class, PERSISTENCE_XML_XSD ); + public void parseXml() { + collectAllEntityMappings(); + determineDefaultAccessTypeAndMetaCompleteness(); + determineXmlAccessTypes(); + if ( !context.isPersistenceUnitCompletelyXmlConfigured() ) { + // need to take annotations into consideration, since they can override xml settings + // we have to at least determine whether any of the xml configured entities is influenced by annotations + determineAnnotationAccessTypes(); + } + + for ( EntityMappings mappings : entityMappings ) { + String defaultPackageName = mappings.getPackage(); + parseEntities( mappings.getEntity(), defaultPackageName ); + parseEmbeddable( mappings.getEmbeddable(), defaultPackageName ); + parseMappedSuperClass( mappings.getMappedSuperclass(), defaultPackageName ); + } + } + + private void collectAllEntityMappings() { + Persistence persistence = parseXml( + context.getPersistenceXmlLocation(), Persistence.class, PERSISTENCE_XML_XSD + ); if ( persistence != null ) { List persistenceUnits = persistence.getPersistenceUnit(); for ( Persistence.PersistenceUnit unit : persistenceUnits ) { List mappingFiles = unit.getMappingFile(); for ( String mappingFile : mappingFiles ) { - parsingOrmXml( mappingFile ); + loadEntityMappings( mappingFile ); } } } - parsingOrmXml( ORM_XML ); // /META-INF/orm.xml is implicit - } - private void parsingOrmXml(String resource) { - EntityMappings mappings = parseXml( resource, EntityMappings.class, ORM_XSD ); - if ( mappings == null ) { - return; + // /META-INF/orm.xml is implicit + loadEntityMappings( ORM_XML ); + + // not really part of the official spec, but the processor allows to specify mapping files directly as + // command line options + for ( String optionalOrmFiles : context.getOrmXmlFiles() ) { + loadEntityMappings( optionalOrmFiles ); } - - AccessType accessType = determineGlobalAccessType( mappings ); - - parseEntities( mappings, accessType ); - parseEmbeddable( mappings, accessType ); - parseMappedSuperClass( mappings, accessType ); } - private void parseEntities(EntityMappings mappings, AccessType accessType) { - String packageName = mappings.getPackage(); - Collection entities = mappings.getEntity(); + private void loadEntityMappings(String resource) { + EntityMappings mapping = parseXml( resource, EntityMappings.class, ORM_XSD ); + if ( mapping != null ) { + entityMappings.add( mapping ); + } + } + + private void parseEntities(Collection entities, String defaultPackageName) { for ( Entity entity : entities ) { - String fullyQualifiedClassName = packageName + "." + entity.getClazz(); + String fqcn = StringUtil.determineFullyQualifiedClassName( defaultPackageName, entity.getClazz() ); - if ( !xmlMappedTypeExists( fullyQualifiedClassName ) ) { + if ( !xmlMappedTypeExists( fqcn ) ) { context.logMessage( Diagnostic.Kind.WARNING, - fullyQualifiedClassName + " is mapped in xml, but class does not exists. Skipping meta model generation." + fqcn + " is mapped in xml, but class does not exists. Skipping meta model generation." ); continue; } XmlMetaEntity metaEntity = new XmlMetaEntity( - entity, packageName, getXmlMappedType( fullyQualifiedClassName ), - context + entity, defaultPackageName, getXmlMappedType( fqcn ), context ); - - if ( context.getMetaEntitiesToProcess().containsKey( fullyQualifiedClassName ) ) { + if ( context.containsMetaEntity( fqcn ) ) { context.logMessage( Diagnostic.Kind.WARNING, - fullyQualifiedClassName + " was already processed once. Skipping second occurance." + fqcn + " was already processed once. Skipping second occurance." ); } - context.getMetaEntitiesToProcess().put( fullyQualifiedClassName, metaEntity ); + context.addMetaEntity( fqcn, metaEntity ); } } - private void parseEmbeddable(EntityMappings mappings, AccessType accessType) { - String packageName = mappings.getPackage(); - Collection embeddables = mappings.getEmbeddable(); + private void parseEmbeddable(Collection embeddables, String defaultPackageName) { for ( org.hibernate.jpamodelgen.xml.jaxb.Embeddable embeddable : embeddables ) { - String fullyQualifiedClassName = packageName + "." + embeddable.getClazz(); + String fqcn = StringUtil.determineFullyQualifiedClassName( defaultPackageName, embeddable.getClazz() ); + // we have to extract the package name from the fqcn. Maybe the entity was setting a fqcn directly + String pkg = StringUtil.packageNameFromFqcn( fqcn ); - if ( !xmlMappedTypeExists( fullyQualifiedClassName ) ) { + if ( !xmlMappedTypeExists( fqcn ) ) { context.logMessage( Diagnostic.Kind.WARNING, - fullyQualifiedClassName + " is mapped in xml, but class does not exists. Skipping meta model generation." + fqcn + " is mapped in xml, but class does not exists. Skipping meta model generation." ); continue; } - XmlMetaEntity metaEntity = new XmlMetaEntity( - embeddable, packageName, getXmlMappedType( fullyQualifiedClassName ), - context - ); - - if ( context.getMetaSuperclassAndEmbeddableToProcess().containsKey( fullyQualifiedClassName ) ) { + XmlMetaEntity metaEntity = new XmlMetaEmbeddable( embeddable, pkg, getXmlMappedType( fqcn ), context ); + if ( context.containsMetaSuperclassOrEmbeddable( fqcn ) ) { context.logMessage( Diagnostic.Kind.WARNING, - fullyQualifiedClassName + " was already processed once. Skipping second occurance." + fqcn + " was already processed once. Skipping second occurance." ); } - context.getMetaSuperclassAndEmbeddableToProcess().put( fullyQualifiedClassName, metaEntity ); + context.addMetaSuperclassOrEmbeddable( fqcn, metaEntity ); } } - - private void parseMappedSuperClass(EntityMappings mappings, AccessType accessType) { - String packageName = mappings.getPackage(); - Collection mappedSuperClasses = mappings.getMappedSuperclass(); + private void parseMappedSuperClass(Collection mappedSuperClasses, String defaultPackageName) { for ( org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass mappedSuperClass : mappedSuperClasses ) { - String fullyQualifiedClassName = packageName + "." + mappedSuperClass.getClazz(); + String fqcn = StringUtil.determineFullyQualifiedClassName( + defaultPackageName, mappedSuperClass.getClazz() + ); + // we have to extract the package name from the fqcn. Maybe the entity was setting a fqcn directly + String pkg = StringUtil.packageNameFromFqcn( fqcn ); - if ( !xmlMappedTypeExists( fullyQualifiedClassName ) ) { + if ( !xmlMappedTypeExists( fqcn ) ) { context.logMessage( Diagnostic.Kind.WARNING, - fullyQualifiedClassName + " is mapped in xml, but class does not exists. Skipping meta model generation." + fqcn + " is mapped in xml, but class does not exists. Skipping meta model generation." ); continue; } - XmlMetaEntity metaEntity = new XmlMetaEntity( - mappedSuperClass, packageName, getXmlMappedType( fullyQualifiedClassName ), - context + XmlMetaEntity metaEntity = new XmlMetaMappedSuperClass( + mappedSuperClass, pkg, getXmlMappedType( fqcn ), context ); - if ( context.getMetaSuperclassAndEmbeddableToProcess().containsKey( fullyQualifiedClassName ) ) { + if ( context.containsMetaSuperclassOrEmbeddable( fqcn ) ) { context.logMessage( Diagnostic.Kind.WARNING, - fullyQualifiedClassName + " was already processed once. Skipping second occurance." + fqcn + " was already processed once. Skipping second occurance." ); } - context.getMetaSuperclassAndEmbeddableToProcess().put( fullyQualifiedClassName, metaEntity ); + context.addMetaSuperclassOrEmbeddable( fqcn, metaEntity ); } } @@ -184,7 +201,8 @@ public class XmlParser { * @param clazz The type of jaxb node to return * @param schemaName The schema to validate against (can be {@code null}); * - * @return The top level jaxb instance contained in the xml file or {@code null} in case the file could not be found. + * @return The top level jaxb instance contained in the xml file or {@code null} in case the file could not be found + * or could not be unmarshalled. */ private T parseXml(String resource, Class clazz, String schemaName) { @@ -274,35 +292,135 @@ public class XmlParser { } private boolean xmlMappedTypeExists(String fullyQualifiedClassName) { - Elements utils = context.getProcessingEnvironment().getElementUtils(); + Elements utils = context.getElementUtils(); return utils.getTypeElement( fullyQualifiedClassName ) != null; } private TypeElement getXmlMappedType(String fullyQualifiedClassName) { - Elements utils = context.getProcessingEnvironment().getElementUtils(); + Elements utils = context.getElementUtils(); return utils.getTypeElement( fullyQualifiedClassName ); } - - private AccessType determineGlobalAccessType(EntityMappings mappings) { - AccessType accessType = DEFAULT_XML_ACCESS_TYPE; - + private AccessType determineEntityAccessType(EntityMappings mappings) { + AccessType accessType = context.getPersistenceUnitDefaultAccessType(); if ( mappings.getAccess() != null ) { accessType = mapXmlAccessTypeToJpaAccessType( mappings.getAccess() ); - return accessType; // no need to check persistence unit default } + return accessType; + } - PersistenceUnitMetadata meta = mappings.getPersistenceUnitMetadata(); - if ( meta != null ) { - PersistenceUnitDefaults persistenceUnitDefaults = meta.getPersistenceUnitDefaults(); - if ( persistenceUnitDefaults != null ) { - org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType = persistenceUnitDefaults.getAccess(); - if ( xmlAccessType != null ) { - accessType = mapXmlAccessTypeToJpaAccessType( xmlAccessType ); + private void determineXmlAccessTypes() { + for ( EntityMappings mappings : entityMappings ) { + String fqcn; + String packageName = mappings.getPackage(); + AccessType defaultAccessType = determineEntityAccessType( mappings ); + + for ( Entity entity : mappings.getEntity() ) { + String name = entity.getClazz(); + fqcn = StringUtil.determineFullyQualifiedClassName( packageName, name ); + AccessType explicitAccessType = null; + org.hibernate.jpamodelgen.xml.jaxb.AccessType type = entity.getAccess(); + if ( type != null ) { + explicitAccessType = mapXmlAccessTypeToJpaAccessType( type ); + } + AccessTypeInformation accessInfo = new AccessTypeInformation( + fqcn, explicitAccessType, defaultAccessType + ); + context.addAccessTypeInformation( fqcn, accessInfo ); + } + + for ( org.hibernate.jpamodelgen.xml.jaxb.Embeddable embeddable : mappings.getEmbeddable() ) { + String name = embeddable.getClazz(); + fqcn = StringUtil.determineFullyQualifiedClassName( packageName, name ); + AccessType explicitAccessType = null; + org.hibernate.jpamodelgen.xml.jaxb.AccessType type = embeddable.getAccess(); + if ( type != null ) { + explicitAccessType = mapXmlAccessTypeToJpaAccessType( type ); + } + AccessTypeInformation accessInfo = new AccessTypeInformation( + fqcn, explicitAccessType, defaultAccessType + ); + context.addAccessTypeInformation( fqcn, accessInfo ); + + } + + for ( org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass mappedSuperClass : mappings.getMappedSuperclass() ) { + String name = mappedSuperClass.getClazz(); + fqcn = StringUtil.determineFullyQualifiedClassName( packageName, name ); + AccessType explicitAccessType = null; + org.hibernate.jpamodelgen.xml.jaxb.AccessType type = mappedSuperClass.getAccess(); + if ( type != null ) { + explicitAccessType = mapXmlAccessTypeToJpaAccessType( type ); + } + AccessTypeInformation accessInfo = new AccessTypeInformation( + fqcn, explicitAccessType, defaultAccessType + ); + context.addAccessTypeInformation( fqcn, accessInfo ); + } + } + } + + private void determineAnnotationAccessTypes() { + for ( EntityMappings mappings : entityMappings ) { + String fqcn; + String packageName = mappings.getPackage(); + + for ( Entity entity : mappings.getEntity() ) { + String name = entity.getClazz(); + fqcn = StringUtil.determineFullyQualifiedClassName( packageName, name ); + TypeElement element = context.getTypeElementForFullyQualifiedName( fqcn ); + if ( element != null ) { + TypeUtils.determineAccessTypeForHierarchy( element, context ); + } + } + + for ( org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass mappedSuperClass : mappings.getMappedSuperclass() ) { + String name = mappedSuperClass.getClazz(); + fqcn = StringUtil.determineFullyQualifiedClassName( packageName, name ); + TypeElement element = context.getTypeElementForFullyQualifiedName( fqcn ); + if ( element != null ) { + TypeUtils.determineAccessTypeForHierarchy( element, context ); } } } - return accessType; + } + + /** + * Determines the default access type as specified in the persistence-unit-defaults as well as whether the + * xml configuration is complete and annotations should be ignored. + *

+ * Note, the spec says: + *

    + *
  • The persistence-unit-metadata element contains metadata for the entire persistence unit. It is + * undefined if this element occurs in multiple mapping files within the same persistence unit.
  • + *
  • If the xml-mapping-metadata-complete subelement is specified, the complete set of mapping + * metadata for the persistence unit is contained in the XML mapping files for the persistence unit, and any + * persistence annotations on the classes are ignored.
  • + *
  • When the xml-mapping-metadata-complete element is specified, any metadata-complete attributes specified + * within the entity, mapped-superclass, and embeddable elements are ignored.
  • + *
+ */ + private void determineDefaultAccessTypeAndMetaCompleteness() { + for ( EntityMappings mappings : entityMappings ) { + PersistenceUnitMetadata meta = mappings.getPersistenceUnitMetadata(); + if ( meta != null ) { + if ( meta.getXmlMappingMetadataComplete() != null ) { + context.setPersistenceUnitCompletelyXmlConfigured( true ); + } + + PersistenceUnitDefaults persistenceUnitDefaults = meta.getPersistenceUnitDefaults(); + if ( persistenceUnitDefaults != null ) { + org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType = persistenceUnitDefaults.getAccess(); + if ( xmlAccessType != null ) { + context.setPersistenceUnitDefaultAccessType( mapXmlAccessTypeToJpaAccessType( xmlAccessType ) ); + } + } + // for simplicity we stop looking for PersistenceUnitMetadata instances. We assume that all files + // are consistent in the data specified in PersistenceUnitMetadata. If not the behaviour is not specified + // anyways. It is up to the JPA provider to handle this when bootstrapping + break; + } + } } private AccessType mapXmlAccessTypeToJpaAccessType(org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType) { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java index bb5a2dcaaa..69e5d65ce8 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java @@ -17,6 +17,10 @@ */ package org.hibernate.jpamodelgen.test.accesstype; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import org.testng.annotations.Test; import org.hibernate.jpamodelgen.test.util.CompilationTest; @@ -32,6 +36,11 @@ import static org.hibernate.jpamodelgen.test.util.TestUtil.assertPresenceOfField */ public class AccessTypeTest extends CompilationTest { + @Test + public void testXmlConfiguredEntityGenerated() { + TestUtil.assertMetamodelClassGeneratedFor( Order.class ); + } + @Test public void testExcludeTransientFieldAndStatic() { TestUtil.assertAbsenceOfFieldInMetamodelFor( Product.class, "nonPersistent" ); @@ -88,7 +97,14 @@ public class AccessTypeTest extends CompilationTest { } @Override - protected String getTestPackage() { - return Product.class.getPackage().getName(); + protected String getPackageNameOfTestSources() { + return AccessTypeTest.class.getPackage().getName(); + } + + @Override + protected Collection getOrmFiles() { + List ormFiles = new ArrayList(); + ormFiles.add( TestUtil.fcnToPath( AccessTypeTest.class.getPackage().getName() ) + "/orm.xml" ); + return ormFiles; } } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Order.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Order.java index 41bba2b35b..750b449cf9 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Order.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Order.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Set; /** - * * @author Max Andersen * @author Hardy Ferentschik * @author Emmanuel Bernard diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/ArrayTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/ArrayTest.java index 59e33bfd51..50301e9bbd 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/ArrayTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/ArrayTest.java @@ -47,7 +47,7 @@ public class ArrayTest extends CompilationTest { } @Override - protected String getTestPackage() { + protected String getPackageNameOfTestSources() { return Image.class.getPackage().getName(); } } \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/TemperatureSamples.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/TemperatureSamples.java index 1b9f07ea95..2b136fe93a 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/TemperatureSamples.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/arraytype/TemperatureSamples.java @@ -20,7 +20,7 @@ package org.hibernate.jpamodelgen.test.arraytype; import javax.persistence.Entity; /** - * @author Hardy Feretnschik + * @author Hardy Ferentschik */ @Entity public class TemperatureSamples { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/elementcollection/ElementCollectionTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/elementcollection/ElementCollectionTest.java index 17460c3b56..426fbb20a3 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/elementcollection/ElementCollectionTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/elementcollection/ElementCollectionTest.java @@ -56,7 +56,7 @@ public class ElementCollectionTest extends CompilationTest { } @Override - protected String getTestPackage() { - return House.class.getPackage().getName(); + protected String getPackageNameOfTestSources() { + return ElementCollectionTest.class.getPackage().getName(); } } \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/generics/GenericsTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/generics/GenericsTest.java index f178a65d01..eb84aec026 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/generics/GenericsTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/generics/GenericsTest.java @@ -35,7 +35,7 @@ public class GenericsTest extends CompilationTest { } @Override - protected String getTestPackage() { - return Parent.class.getPackage().getName(); + protected String getPackageNameOfTestSources() { + return GenericsTest.class.getPackage().getName(); } } \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/inheritance/InheritanceTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/inheritance/InheritanceTest.java index 4dc7777211..9d98ecf443 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/inheritance/InheritanceTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/inheritance/InheritanceTest.java @@ -40,7 +40,7 @@ public class InheritanceTest extends CompilationTest { } @Override - protected String getTestPackage() { - return Customer.class.getPackage().getName(); + protected String getPackageNameOfTestSources() { + return InheritanceTest.class.getPackage().getName(); } } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Car.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Car.java new file mode 100644 index 0000000000..5cf7315b76 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Car.java @@ -0,0 +1,42 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +/** + * @author Hardy Ferentschik + */ +public class Car extends Vehicle { + private String make; + + public int getHorsePower() { + return 0; + } + + public void setHorsePower(int horsePower) { + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } +} + + diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java new file mode 100644 index 0000000000..62c8831346 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Coordinates.java @@ -0,0 +1,31 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Embeddable; + +/** + * @author Hardy Ferentschik + */ +@Embeddable +public class Coordinates { + public float longitude; + public float latitude; +} + + diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Insurance.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Insurance.java new file mode 100644 index 0000000000..1e954cc219 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Insurance.java @@ -0,0 +1,47 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Embeddable; + +/** + * @author Hardy Ferentschik + */ +@Embeddable +public class Insurance { + String number; + String policyNumber; + + public String getPolicyNumber() { + return policyNumber; + } + + public void setPolicyNumber(String policyNumber) { + this.policyNumber = policyNumber; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } +} + + diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java new file mode 100644 index 0000000000..4792f913a3 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Location.java @@ -0,0 +1,73 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * @author Hardy Ferentschik + */ +@Entity +@Access(AccessType.FIELD) +public class Location { + @Id + private long id; + private String description; + // implicitly embedded + private Coordinates coordinates; + @Embedded + private ZeroCoordinates zeroCoordinates; + + public Coordinates getCoordinates() { + return coordinates; + } + + public void setCoordinates(Coordinates coordinates) { + this.coordinates = coordinates; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public ZeroCoordinates getZeroCoordinates() { + return zeroCoordinates; + } + + public void setZeroCoordinates(ZeroCoordinates zeroCoordinates) { + this.zeroCoordinates = zeroCoordinates; + } +} + + diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java new file mode 100644 index 0000000000..78c7733bc0 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedConfigurationTest.java @@ -0,0 +1,111 @@ +// $Id: MixedModeMappingTest.java 18683 2010-02-02 21:51:40Z 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.mixedmode; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.testng.annotations.Test; + +import org.hibernate.jpamodelgen.test.util.CompilationTest; +import org.hibernate.jpamodelgen.test.util.TestUtil; + +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAbsenceOfFieldInMetamodelFor; +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 MixedConfigurationTest extends CompilationTest { + @Test + public void testDefaultAccessTypeApplied() { + assertMetamodelClassGeneratedFor( Vehicle.class ); + assertMetamodelClassGeneratedFor( Car.class ); + + assertAbsenceOfFieldInMetamodelFor( + Car.class, "horsePower", "'horsePower' should not appear in metamodel since it does have no field." + ); + } + + @Test + public void testExplicitXmlConfiguredAccessTypeApplied() { + assertMetamodelClassGeneratedFor( Vehicle.class ); + assertMetamodelClassGeneratedFor( Truck.class ); + + assertPresenceOfFieldInMetamodelFor( + Truck.class, "horsePower", "Property 'horsePower' has explicit access type and should be in metamodel" + ); + assertAttributeTypeInMetaModelFor( Truck.class, "horsePower", Integer.class, "Wrong meta model type" ); + } + + @Test + public void testMixedConfiguration() { + assertMetamodelClassGeneratedFor( RentalCar.class ); + assertMetamodelClassGeneratedFor( RentalCompany.class ); + + assertPresenceOfFieldInMetamodelFor( + RentalCar.class, "company", "Property 'company' should be included due to xml configuration" + ); + assertAttributeTypeInMetaModelFor( RentalCar.class, "company", RentalCompany.class, "Wrong meta model type" ); + + assertPresenceOfFieldInMetamodelFor( + RentalCar.class, "insurance", "Property 'insurance' should be included since it is an embeddable" + ); + assertAttributeTypeInMetaModelFor( RentalCar.class, "insurance", Insurance.class, "Wrong meta model type" ); + } + + @Test + public void testAccessTypeForXmlConfiguredEmbeddables() { + assertMetamodelClassGeneratedFor( Coordinates.class ); + assertPresenceOfFieldInMetamodelFor( + Coordinates.class, "longitude", "field exists and should be in metamodel" + ); + assertPresenceOfFieldInMetamodelFor( Coordinates.class, "latitude", "field exists and should be in metamodel" ); + + assertMetamodelClassGeneratedFor( ZeroCoordinates.class ); + assertAbsenceOfFieldInMetamodelFor( + ZeroCoordinates.class, + "longitude", + "Field access should be used, but ZeroCoordinates does not define fields" + ); + assertAbsenceOfFieldInMetamodelFor( + ZeroCoordinates.class, + "latitude", + "Field access should be used, but ZeroCoordinates does not define fields" + ); + } + + @Override + protected String getPackageNameOfTestSources() { + return MixedConfigurationTest.class.getPackage().getName(); + } + + @Override + protected Collection getOrmFiles() { + List ormFiles = new ArrayList(); + String dir = TestUtil.fcnToPath( MixedConfigurationTest.class.getPackage().getName() ); + ormFiles.add( dir + "/car.xml" ); + ormFiles.add( dir + "/rentalcar.xml" ); + ormFiles.add( dir + "/truck.xml" ); + ormFiles.add( dir + "/coordinates.xml" ); + return ormFiles; + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Person.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Person.java new file mode 100644 index 0000000000..622e45e328 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Person.java @@ -0,0 +1,49 @@ +// $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.mixedmode; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Person { + @Id + @GeneratedValue + private long id; + private String name; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCar.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCar.java new file mode 100644 index 0000000000..5f5b9e3b21 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCar.java @@ -0,0 +1,71 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Entity; + + +/** + * @author Hardy Ferentschik + */ +@Entity +public class RentalCar extends Car { + private RentalCompany company; + + private CURRENTLY_HIRED hired; + + private Character[] chassisNumber; + + private Insurance insurance; + + public RentalCompany getCompany() { + return company; + } + + public void setCompany(RentalCompany company) { + this.company = company; + } + + public Character[] getChassisNumber() { + return chassisNumber; + } + + public void setChassisNumber(Character[] chassisNumber) { + this.chassisNumber = chassisNumber; + } + + public CURRENTLY_HIRED getHired() { + return hired; + } + + public void setHired(CURRENTLY_HIRED hired) { + this.hired = hired; + } + + public Insurance getInsurance() { + return insurance; + } + + public void setInsurance(Insurance insurance) { + this.insurance = insurance; + } + + enum CURRENTLY_HIRED { + YES, NO + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCompany.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCompany.java new file mode 100644 index 0000000000..e212d30c25 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/RentalCompany.java @@ -0,0 +1,50 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class RentalCompany { + @Id + @GeneratedValue + private long id; + + private String name; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Truck.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Truck.java new file mode 100644 index 0000000000..f39ef3f0e8 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Truck.java @@ -0,0 +1,41 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + + +/** + * @author Hardy Ferentschik + */ +public class Truck extends Vehicle { + private String make; + + public int getHorsePower() { + return 0; + } + + public void setHorsePower(int horsePower) { + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Vehicle.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Vehicle.java new file mode 100644 index 0000000000..f05fb2261f --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/Vehicle.java @@ -0,0 +1,43 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class Vehicle { + // default access type for classes in this hierarchy is FIELD + @Id + @GeneratedValue + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} + + diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/XmlMetaCompleteTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/XmlMetaCompleteTest.java new file mode 100644 index 0000000000..43e2ea6801 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/XmlMetaCompleteTest.java @@ -0,0 +1,53 @@ +// $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.mixedmode; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.testng.annotations.Test; + +import org.hibernate.jpamodelgen.test.util.CompilationTest; +import org.hibernate.jpamodelgen.test.util.TestUtil; + +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAbsenceOfFieldInMetamodelFor; +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor; + +/** + * @author Hardy Ferentschik + */ +public class XmlMetaCompleteTest extends CompilationTest { + @Test + public void testXmlConfiguredEmbeddedClassGenerated() { + assertMetamodelClassGeneratedFor( Person.class ); + assertAbsenceOfFieldInMetamodelFor( Person.class, "name" ); + } + + @Override + protected String getPackageNameOfTestSources() { + return XmlMetaCompleteTest.class.getPackage().getName(); + } + + @Override + protected Collection getOrmFiles() { + List ormFiles = new ArrayList(); + ormFiles.add( TestUtil.fcnToPath( XmlMetaCompleteTest.class.getPackage().getName() ) + "/orm.xml" ); + return ormFiles; + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java new file mode 100644 index 0000000000..a965567876 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/ZeroCoordinates.java @@ -0,0 +1,41 @@ +// $Id:$ +/* +* JBoss, Home of Professional Open Source +* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.mixedmode; + +import javax.persistence.Embeddable; + + +/** + * @author Hardy Ferentschik + */ +@Embeddable +public class ZeroCoordinates { + public float getLatitude() { + return 0f; + } + + public void setLatitude(float latitude) { + } + + public float getLongitude() { + return 0f; + } + + public void setLongitude(float longitude) { + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/DeskWithRawType.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/DeskWithRawType.java similarity index 96% rename from tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/DeskWithRawType.java rename to tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/DeskWithRawType.java index 2a00521ed4..9498391dfe 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/DeskWithRawType.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/DeskWithRawType.java @@ -1,4 +1,4 @@ -package org.hibernate.jpamodelgen.test.rawTypes; +package org.hibernate.jpamodelgen.test.rawtypes; import java.util.Collection; import javax.persistence.Basic; diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/EmployeeWithRawType.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/EmployeeWithRawType.java similarity index 94% rename from tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/EmployeeWithRawType.java rename to tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/EmployeeWithRawType.java index 599b7f43a6..d4ef6080d3 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/EmployeeWithRawType.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/EmployeeWithRawType.java @@ -1,4 +1,4 @@ -package org.hibernate.jpamodelgen.test.rawTypes; +package org.hibernate.jpamodelgen.test.rawtypes; import java.util.Collection; import javax.persistence.Basic; diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/RawTypesTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/RawTypesTest.java similarity index 88% rename from tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/RawTypesTest.java rename to tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/RawTypesTest.java index be140b7529..436d7bc6f3 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawTypes/RawTypesTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/rawtypes/RawTypesTest.java @@ -1,4 +1,4 @@ -// $Id$ +// $Id: RawTypesTest.java 18664 2010-01-28 16:56:51Z hardy.ferentschik $ /* * JBoss, Home of Professional Open Source * Copyright 2008, Red Hat Middleware LLC, and individual contributors @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.hibernate.jpamodelgen.test.rawTypes; +package org.hibernate.jpamodelgen.test.rawtypes; import org.testng.annotations.Test; @@ -35,7 +35,7 @@ public class RawTypesTest extends CompilationTest { } @Override - protected String getTestPackage() { + protected String getPackageNameOfTestSources() { return DeskWithRawType.class.getPackage().getName(); } } \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java index a830836864..5d4d51c48c 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java @@ -19,34 +19,47 @@ package org.hibernate.jpamodelgen.test.util; import java.io.File; import java.io.FilenameFilter; -import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; +import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeClass; + +import org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor; + import static org.testng.FileAssert.fail; /** * @author Hardy Ferentschik */ public abstract class CompilationTest { - + private static final Logger log = LoggerFactory.getLogger( CompilationTest.class ); private static final String PATH_SEPARATOR = System.getProperty( "file.separator" ); + private static final String ANNOTATION_PROCESSOR_OPTION_PREFIX = "-A"; + private static final String SOURCE_BASE_DIR_PROPERTY = "sourceBaseDir"; + private static final String OUT_BASE_DIR_PROPERTY = "outBaseDir"; private static final String sourceBaseDir; private static final String outBaseDir; static { - String tmp = System.getProperty( "sourceBaseDir" ); + String tmp = System.getProperty( SOURCE_BASE_DIR_PROPERTY ); if ( tmp == null ) { fail( "The system property sourceBaseDir has to be set and point to the base directory of the test java sources." ); } sourceBaseDir = tmp; - tmp = System.getProperty( "outBaseDir" ); + tmp = System.getProperty( OUT_BASE_DIR_PROPERTY ); if ( tmp == null ) { fail( "The system property outBaseDir has to be set and point to the base directory of the test output directory." ); } @@ -54,17 +67,11 @@ public abstract class CompilationTest { } public CompilationTest() { - try { - TestUtil.clearOutputFolder(); - compile(); - } - catch ( Exception e ) { - e.printStackTrace( ); - fail( "Unable to compile test sources. " + e.getMessage() ); - } } - private void compile() throws IOException { + @BeforeClass + protected void compile() throws Exception { + TestUtil.deleteGeneratedSourceFiles( new File( outBaseDir ) ); List options = createJavaOptions(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); @@ -82,6 +89,7 @@ public abstract class CompilationTest { compilationUnits = fileManager.getJavaFileObjectsFromFiles( getCompilationUnits( outBaseDir ) ); + options.add( "-proc:none" ); // for the second compile skip the processor compileSources( options, compiler, diagnostics, fileManager, compilationUnits ); fileManager.close(); } @@ -91,24 +99,46 @@ public abstract class CompilationTest { null, fileManager, diagnostics, options, null, compilationUnits ); task.call(); -// for ( Diagnostic diagnostic : diagnostics.getDiagnostics() ) { -// System.out.println( diagnostic.getMessage( null ) ); -// } + for ( Diagnostic diagnostic : diagnostics.getDiagnostics() ) { + log.debug( diagnostic.getMessage( null ) ); + } } private List createJavaOptions() { - // TODO - // passing any other options as -d seems to throw IllegalArgumentExceptions. I would like to set -s for example - // in order to see whether recursive recompilation would work then. Also '-proc only' could be interesting List options = new ArrayList(); options.add( "-d" ); options.add( outBaseDir ); + + // pass orm files if specified + if ( !getOrmFiles().isEmpty() ) { + StringBuilder builder = new StringBuilder(); + builder.append( ANNOTATION_PROCESSOR_OPTION_PREFIX ); + builder.append( JPAMetaModelEntityProcessor.ORM_XML_OPTION ); + builder.append( "=" ); + for ( String ormFile : getOrmFiles() ) { + builder.append( ormFile ); + builder.append( "," ); + } + builder.deleteCharAt( builder.length() - 1 ); + options.add( builder.toString() ); + } + + // add any additional options specified by the test + for ( Map.Entry entry : getProcessorOptions().entrySet() ) { + StringBuilder builder = new StringBuilder(); + builder.append( ANNOTATION_PROCESSOR_OPTION_PREFIX ); + builder.append( entry.getKey() ); + builder.append( "=" ); + builder.append( entry.getValue() ); + options.add( builder.toString() ); + } + options.add( "-Adebug=true" ); return options; } private List getCompilationUnits(String baseDir) { List javaFiles = new ArrayList(); - String packageDirName = baseDir + PATH_SEPARATOR + getTestPackage().replace( ".", PATH_SEPARATOR ); + String packageDirName = baseDir + PATH_SEPARATOR + getPackageNameOfTestSources().replace( ".", PATH_SEPARATOR ); File packageDir = new File( packageDirName ); FilenameFilter javaFileFilter = new FilenameFilter() { @Override @@ -117,16 +147,22 @@ public abstract class CompilationTest { } }; final File[] files = packageDir.listFiles( javaFileFilter ); - if (files == null) { + if ( files == null ) { throw new RuntimeException( "Cannot find package directory (is your base dir correct?): " + packageDirName ); } - for ( File file : files ) { - javaFiles.add( file ); - } + javaFiles.addAll( Arrays.asList( files ) ); return javaFiles; } - abstract protected String getTestPackage(); + abstract protected String getPackageNameOfTestSources(); + + protected Map getProcessorOptions() { + return Collections.emptyMap(); + } + + protected Collection getOrmFiles() { + return Collections.emptyList(); + } } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java index 14fa9f792e..c89e8d51b8 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java @@ -18,11 +18,14 @@ package org.hibernate.jpamodelgen.test.util; import java.io.File; +import java.io.FileFilter; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testng.Assert; import static org.testng.Assert.assertEquals; @@ -34,8 +37,9 @@ import static org.testng.FileAssert.fail; * @author Hardy Ferentschik */ public class TestUtil { - + private static final Logger log = LoggerFactory.getLogger( TestUtil.class ); private static final String PATH_SEPARATOR = System.getProperty( "file.separator" ); + private static final String PACKAGE_SEPARATOR = "."; private static final String META_MODEL_CLASS_POSTFIX = "_"; private static final String outBaseDir; @@ -50,11 +54,23 @@ public class TestUtil { private TestUtil() { } - public static void clearOutputFolder() { - File outDir = new File( outBaseDir ); - File[] files = outDir.listFiles(); - for ( File file : files ) { - file.delete(); + public static void deleteGeneratedSourceFiles(File path) { + if ( path.exists() ) { + File[] files = path.listFiles( new MetaModelFilenameFilter() ); + for ( File file : files ) { + if ( file.isDirectory() ) { + deleteGeneratedSourceFiles( file ); + } + else { + boolean success = file.delete(); + if ( success ) { + log.debug( file.getAbsolutePath() + " deleted successfully" ); + } + else { + log.debug( "Failed to delete generated source file" + file.getAbsolutePath() ); + } + } + } } } @@ -78,7 +94,7 @@ public class TestUtil { assertNotNull( clazz, "Class parameter cannot be null" ); String metaModelClassName = clazz.getName() + META_MODEL_CLASS_POSTFIX; // generate the file name - String fileName = metaModelClassName.replace( ".", PATH_SEPARATOR ); + String fileName = metaModelClassName.replace( PACKAGE_SEPARATOR, PATH_SEPARATOR ); fileName = fileName.concat( ".java" ); File sourceFile = new File( outBaseDir + PATH_SEPARATOR + fileName ); assertFalse( sourceFile.exists(), "There should be no source file: " + fileName ); @@ -98,14 +114,18 @@ public class TestUtil { public static void assertAttributeTypeInMetaModelFor(Class clazz, String fieldName, Class expectedType, String errorString) { Field field = getFieldFromMetamodelFor( clazz, fieldName ); - assertNotNull( field ); + assertNotNull( field, "Cannot find field '" + fieldName + "' in " + clazz.getName() ); ParameterizedType type = ( ParameterizedType ) field.getGenericType(); Type actualType = type.getActualTypeArguments()[1]; if ( expectedType.isArray() ) { expectedType = expectedType.getComponentType(); actualType = ( ( GenericArrayType ) actualType ).getGenericComponentType(); } - assertEquals( actualType, expectedType, errorString ); + assertEquals( + actualType, + expectedType, + "Types do not match: " + errorString + ); } public static void assertMapAttributesInMetaModelFor(Class clazz, String fieldName, Class expectedMapKey, Class expectedMapValue, String errorString) { @@ -157,6 +177,23 @@ public class TestUtil { } return field; } + + public static String fcnToPath(String fcn) { + return fcn.replace( PACKAGE_SEPARATOR, PATH_SEPARATOR ); + } + + private static class MetaModelFilenameFilter implements FileFilter { + @Override + public boolean accept(File pathName) { + if ( pathName.isDirectory() ) { + return true; + } + else { + return pathName.getAbsolutePath().endsWith( "_.java" ) + || pathName.getAbsolutePath().endsWith( "_.class" ); + } + } + } } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/IgnoreInvalidXmlTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/IgnoreInvalidXmlTest.java new file mode 100644 index 0000000000..54ef06b30e --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/IgnoreInvalidXmlTest.java @@ -0,0 +1,57 @@ +// $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.xmlmapped; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.testng.annotations.Test; + +import org.hibernate.jpamodelgen.test.util.CompilationTest; +import org.hibernate.jpamodelgen.test.util.TestUtil; + +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor; + +/** + * @author Hardy Ferentschik + */ +public class IgnoreInvalidXmlTest extends CompilationTest { + @Test + public void testInvalidXmlFilesGetIgnored() { + // this is only a indirect test, but if the invalid xml files would cause the processor to abort the + // meta class would not have been generated + assertMetamodelClassGeneratedFor( Superhero.class ); + } + + @Override + protected String getPackageNameOfTestSources() { + return IgnoreInvalidXmlTest.class.getPackage().getName(); + } + + @Override + protected Collection getOrmFiles() { + List ormFiles = new ArrayList(); + String packageName = TestUtil.fcnToPath( IgnoreInvalidXmlTest.class.getPackage().getName() ); + ormFiles.add( packageName + "/orm.xml" ); + ormFiles.add( packageName + "/jpa1-orm.xml" ); + ormFiles.add( packageName + "/malformed-mapping.xml" ); + ormFiles.add( packageName + "/non-existend-class.xml" ); + return ormFiles; + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/LivingBeing.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/LivingBeing.java index a8de6332ad..2a2d0d3355 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/LivingBeing.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/LivingBeing.java @@ -21,14 +21,14 @@ package org.hibernate.jpamodelgen.test.xmlmapped; * @author Hardy Ferentschik */ public class LivingBeing { - boolean isReallyAlive; + boolean reallyAlive; public boolean isReallyAlive() { - return isReallyAlive; + return reallyAlive; } public void setReallyAlive(boolean reallyAlive) { - isReallyAlive = reallyAlive; + this.reallyAlive = reallyAlive; } public int nonPersistent() { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java index 5f7299e3a9..9e79ee74f5 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java @@ -17,9 +17,14 @@ */ package org.hibernate.jpamodelgen.test.xmlmapped; +import java.util.HashMap; +import java.util.Map; + import org.testng.annotations.Test; +import org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor; import org.hibernate.jpamodelgen.test.util.CompilationTest; +import org.hibernate.jpamodelgen.test.util.TestUtil; import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAttributeTypeInMetaModelFor; import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor; @@ -84,7 +89,6 @@ public class XmlMappingTest extends CompilationTest { assertAttributeTypeInMetaModelFor( Boy.class, "nickNames", String.class, "target class overridden in xml" ); } - @Test public void testClassHierarchy() { assertMetamodelClassGeneratedFor( Mammal.class ); @@ -98,7 +102,17 @@ public class XmlMappingTest extends CompilationTest { } @Override - protected String getTestPackage() { - return Address.class.getPackage().getName(); + protected String getPackageNameOfTestSources() { + return XmlMappingTest.class.getPackage().getName(); + } + + @Override + protected Map getProcessorOptions() { + Map properties = new HashMap(); + properties.put( + JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION, + TestUtil.fcnToPath( XmlMappingTest.class.getPackage().getName() ) + "/persistence.xml" + ); + return properties; } } \ No newline at end of file diff --git a/tooling/metamodel-generator/src/test/resources/META-INF/persistence.xml b/tooling/metamodel-generator/src/test/resources/META-INF/persistence.xml index b755fe4208..d52a1685e4 100644 --- a/tooling/metamodel-generator/src/test/resources/META-INF/persistence.xml +++ b/tooling/metamodel-generator/src/test/resources/META-INF/persistence.xml @@ -1,15 +1,8 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence.xsd" version="2.0"> Test persistence unit - /META-INF/dummy.xml - /META-INF/malformed-mapping-xml.xml - /META-INF/jpa1-orm.xml - /org/hibernate/jpamodelgen/test/xmlmapped/address.xml - /org/hibernate/jpamodelgen/test/xmlmapped/building.xml - /org/hibernate/jpamodelgen/test/xmlmapped/mammal.xml - /org/hibernate/jpamodelgen/test/xmlmapped/boy.xml diff --git a/tooling/metamodel-generator/src/test/resources/log4j.properties b/tooling/metamodel-generator/src/test/resources/log4j.properties new file mode 100644 index 0000000000..2be85f43d4 --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/log4j.properties @@ -0,0 +1,24 @@ +### direct log messages to stdout ### +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file hibernate.log ### +log4j.appender.file=org.apache.log4j.FileAppender +log4j.appender.file.File=hibernate.log +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to socket - chainsaw ### +log4j.appender.socket=org.apache.log4j.net.SocketAppender +log4j.appender.socket.remoteHost=localhost +log4j.appender.socket.port=4560 +log4j.appender.socket.locationInfo=true + + +### set log levels - for more verbose logging change 'info' to 'debug' ### +log4j.rootLogger=debug, stdout + +#log4j.logger.org.hibernate.jpamodelgen.test.util.CompilationTest=trace + diff --git a/tooling/metamodel-generator/src/test/resources/META-INF/orm.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/accesstype/orm.xml similarity index 94% rename from tooling/metamodel-generator/src/test/resources/META-INF/orm.xml rename to tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/accesstype/orm.xml index 9b504d313f..66627ef8bd 100644 --- a/tooling/metamodel-generator/src/test/resources/META-INF/orm.xml +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/accesstype/orm.xml @@ -6,7 +6,6 @@ version="2.0" > org.hibernate.jpamodelgen.test.accesstype - @@ -23,7 +22,6 @@ - diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/car.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/car.xml new file mode 100644 index 0000000000..534a51dcbf --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/car.xml @@ -0,0 +1,17 @@ + + + + + foo.bar + + + + + + + + diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml new file mode 100644 index 0000000000..a2c9ec3368 --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/coordinates.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml new file mode 100644 index 0000000000..505ac838b9 --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml @@ -0,0 +1,18 @@ + + + + + + + org.hibernate.jpamodelgen.test.mixedmode + + + + + + + diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/rentalcar.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/rentalcar.xml new file mode 100644 index 0000000000..1ccfff0855 --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/rentalcar.xml @@ -0,0 +1,16 @@ + + + + + foo.bar + + + + + + + diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/truck.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/truck.xml new file mode 100644 index 0000000000..14d81abfaa --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/truck.xml @@ -0,0 +1,17 @@ + + + + + foo.bar + + + + + + + + diff --git a/tooling/metamodel-generator/src/test/resources/META-INF/jpa1-orm.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/jpa1-orm.xml similarity index 100% rename from tooling/metamodel-generator/src/test/resources/META-INF/jpa1-orm.xml rename to tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/jpa1-orm.xml diff --git a/tooling/metamodel-generator/src/test/resources/META-INF/malformed-mapping-xml.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/malformed-mapping.xml similarity index 100% rename from tooling/metamodel-generator/src/test/resources/META-INF/malformed-mapping-xml.xml rename to tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/malformed-mapping.xml diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/mammal.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/mammal.xml index 57216ccd1c..1b032c4b5b 100644 --- a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/mammal.xml +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/mammal.xml @@ -8,7 +8,7 @@ org.hibernate.jpamodelgen.test.xmlmapped - + diff --git a/tooling/metamodel-generator/src/test/resources/META-INF/dummy.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/non-existend-class.xml similarity index 100% rename from tooling/metamodel-generator/src/test/resources/META-INF/dummy.xml rename to tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/non-existend-class.xml diff --git a/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/persistence.xml b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/persistence.xml new file mode 100644 index 0000000000..611a222b87 --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/org/hibernate/jpamodelgen/test/xmlmapped/persistence.xml @@ -0,0 +1,11 @@ + + + + /org/hibernate/jpamodelgen/test/xmlmapped/address.xml + /org/hibernate/jpamodelgen/test/xmlmapped/building.xml + /org/hibernate/jpamodelgen/test/xmlmapped/mammal.xml + /org/hibernate/jpamodelgen/test/xmlmapped/boy.xml + + diff --git a/tooling/metamodel-generator/src/test/suite/unit-tests.xml b/tooling/metamodel-generator/src/test/suite/unit-tests.xml index 91528da7bc..1115776fec 100644 --- a/tooling/metamodel-generator/src/test/suite/unit-tests.xml +++ b/tooling/metamodel-generator/src/test/suite/unit-tests.xml @@ -8,7 +8,8 @@ - + +