HHH-16633 fix an issue with the lifecycle of annotation processing
we could not see typesafe references to static strings we generate
This commit is contained in:
parent
a4d8580606
commit
9512077462
|
@ -13,6 +13,7 @@ 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.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
|
@ -36,7 +37,7 @@ public final class Context {
|
|||
private static final String DEFAULT_PERSISTENCE_XML_LOCATION = "/META-INF/persistence.xml";
|
||||
|
||||
/**
|
||||
* Used for keeping track of parsed entities and mapped super classes (xml + annotations).
|
||||
* Used for keeping track of parsed entities and mapped super classes (XML + annotations).
|
||||
*/
|
||||
private final Map<String, Metamodel> metaEntities = new HashMap<>();
|
||||
|
||||
|
@ -50,7 +51,9 @@ public final class Context {
|
|||
|
||||
private final Map<String, AccessTypeInformation> accessTypeInformation = new HashMap<>();
|
||||
|
||||
private final ProcessingEnvironment pe;
|
||||
private final Set<CharSequence> elementsToRedo = new HashSet<>();
|
||||
|
||||
private final ProcessingEnvironment processingEnvironment;
|
||||
private final boolean logDebug;
|
||||
private final boolean lazyXmlParsing;
|
||||
private final String persistenceXmlLocation;
|
||||
|
@ -68,12 +71,12 @@ public final class Context {
|
|||
private AccessType persistenceUnitDefaultAccessType;
|
||||
|
||||
// keep track of all classes for which model have been generated
|
||||
private final Collection<String> generatedModelClasses = new HashSet<String>();
|
||||
private final Collection<String> generatedModelClasses = new HashSet<>();
|
||||
|
||||
public Context(ProcessingEnvironment pe) {
|
||||
this.pe = pe;
|
||||
public Context(ProcessingEnvironment processingEnvironment) {
|
||||
this.processingEnvironment = processingEnvironment;
|
||||
|
||||
String persistenceXmlOption = pe.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION );
|
||||
String persistenceXmlOption = processingEnvironment.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION );
|
||||
if ( persistenceXmlOption != null ) {
|
||||
if ( !persistenceXmlOption.startsWith("/") ) {
|
||||
persistenceXmlOption = "/" + persistenceXmlOption;
|
||||
|
@ -84,7 +87,7 @@ public final class Context {
|
|||
persistenceXmlLocation = DEFAULT_PERSISTENCE_XML_LOCATION;
|
||||
}
|
||||
|
||||
String ormXmlOption = pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION );
|
||||
String ormXmlOption = processingEnvironment.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION );
|
||||
if ( ormXmlOption != null ) {
|
||||
ormXmlFiles = new ArrayList<>();
|
||||
for ( String ormFile : ormXmlOption.split( "," ) ) {
|
||||
|
@ -98,12 +101,12 @@ public final class Context {
|
|||
ormXmlFiles = Collections.emptyList();
|
||||
}
|
||||
|
||||
lazyXmlParsing = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.LAZY_XML_PARSING ) );
|
||||
logDebug = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ) );
|
||||
lazyXmlParsing = Boolean.parseBoolean( processingEnvironment.getOptions().get( JPAMetaModelEntityProcessor.LAZY_XML_PARSING ) );
|
||||
logDebug = Boolean.parseBoolean( processingEnvironment.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ) );
|
||||
}
|
||||
|
||||
public ProcessingEnvironment getProcessingEnvironment() {
|
||||
return pe;
|
||||
return processingEnvironment;
|
||||
}
|
||||
|
||||
public boolean addInjectAnnotation() {
|
||||
|
@ -139,11 +142,11 @@ public final class Context {
|
|||
}
|
||||
|
||||
public Elements getElementUtils() {
|
||||
return pe.getElementUtils();
|
||||
return processingEnvironment.getElementUtils();
|
||||
}
|
||||
|
||||
public Types getTypeUtils() {
|
||||
return pe.getTypeUtils();
|
||||
return processingEnvironment.getTypeUtils();
|
||||
}
|
||||
|
||||
public String getPersistenceXmlLocation() {
|
||||
|
@ -207,7 +210,7 @@ public final class Context {
|
|||
}
|
||||
|
||||
public TypeElement getTypeElementForFullyQualifiedName(String fqcn) {
|
||||
Elements elementUtils = pe.getElementUtils();
|
||||
Elements elementUtils = processingEnvironment.getElementUtils();
|
||||
return elementUtils.getTypeElement( fqcn );
|
||||
}
|
||||
|
||||
|
@ -219,9 +222,21 @@ public final class Context {
|
|||
return generatedModelClasses.contains( name );
|
||||
}
|
||||
|
||||
public Set<CharSequence> getElementsToRedo() {
|
||||
return elementsToRedo;
|
||||
}
|
||||
|
||||
public void addElementToRedo(CharSequence qualifiedName) {
|
||||
elementsToRedo.add( qualifiedName );
|
||||
}
|
||||
|
||||
public void removeElementToRedo(CharSequence qualifiedName) {
|
||||
elementsToRedo.remove( qualifiedName );
|
||||
}
|
||||
|
||||
public void logMessage(Diagnostic.Kind type, String message) {
|
||||
if ( logDebug || type != Diagnostic.Kind.OTHER ) {
|
||||
pe.getMessager().printMessage( type, message );
|
||||
processingEnvironment.getMessager().printMessage( type, message );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.jpamodelgen;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
|
@ -18,6 +19,7 @@ import javax.lang.model.SourceVersion;
|
|||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
|
@ -29,6 +31,7 @@ import javax.tools.Diagnostic;
|
|||
|
||||
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
|
||||
import org.hibernate.jpamodelgen.annotation.AnnotationMetaPackage;
|
||||
import org.hibernate.jpamodelgen.annotation.ProcessLaterException;
|
||||
import org.hibernate.jpamodelgen.model.Metamodel;
|
||||
import org.hibernate.jpamodelgen.util.Constants;
|
||||
import org.hibernate.jpamodelgen.util.StringUtil;
|
||||
|
@ -37,8 +40,10 @@ import org.hibernate.jpamodelgen.xml.JpaDescriptorParser;
|
|||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static javax.lang.model.util.ElementFilter.fieldsIn;
|
||||
import static javax.lang.model.util.ElementFilter.methodsIn;
|
||||
import static org.hibernate.jpamodelgen.util.Constants.FIND;
|
||||
import static org.hibernate.jpamodelgen.util.Constants.HQL;
|
||||
import static org.hibernate.jpamodelgen.util.Constants.SQL;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
|
@ -87,46 +92,20 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
public static final String ADD_GENERATED_ANNOTATION = "addGeneratedAnnotation";
|
||||
public static final String ADD_SUPPRESS_WARNINGS_ANNOTATION = "addSuppressWarningsAnnotation";
|
||||
|
||||
private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = Boolean.FALSE;
|
||||
private static final boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false;
|
||||
|
||||
private Context context;
|
||||
|
||||
@Override
|
||||
public void init(ProcessingEnvironment env) {
|
||||
super.init( env );
|
||||
context = new Context( env );
|
||||
public synchronized void init(ProcessingEnvironment processingEnvironment) {
|
||||
super.init( processingEnvironment );
|
||||
context = new Context( processingEnvironment );
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.NOTE, "Hibernate JPA 2 Static-Metamodel Generator " + Version.getVersionString()
|
||||
Diagnostic.Kind.NOTE,
|
||||
"Hibernate/JPA static Metamodel Generator " + Version.getVersionString()
|
||||
);
|
||||
|
||||
PackageElement jakartaInjectPackage =
|
||||
context.getProcessingEnvironment().getElementUtils()
|
||||
.getPackageElement( "jakarta.inject" );
|
||||
context.setAddInjectAnnotation( jakartaInjectPackage != null );
|
||||
|
||||
String tmp = env.getOptions().get( JPAMetaModelEntityProcessor.ADD_GENERATED_ANNOTATION );
|
||||
if ( tmp != null ) {
|
||||
boolean addGeneratedAnnotation = Boolean.parseBoolean( tmp );
|
||||
context.setAddGeneratedAnnotation( addGeneratedAnnotation );
|
||||
}
|
||||
else {
|
||||
PackageElement jakartaAnnotationPackage =
|
||||
context.getProcessingEnvironment().getElementUtils()
|
||||
.getPackageElement( "jakarta.annotation" );
|
||||
context.setAddGeneratedAnnotation( jakartaAnnotationPackage != null );
|
||||
}
|
||||
|
||||
tmp = env.getOptions().get( JPAMetaModelEntityProcessor.ADD_GENERATION_DATE );
|
||||
boolean addGenerationDate = Boolean.parseBoolean( tmp );
|
||||
context.setAddGenerationDate( addGenerationDate );
|
||||
|
||||
tmp = env.getOptions().get( JPAMetaModelEntityProcessor.ADD_SUPPRESS_WARNINGS_ANNOTATION );
|
||||
boolean addSuppressWarningsAnnotation = Boolean.parseBoolean( tmp );
|
||||
context.setAddSuppressWarningsAnnotation( addSuppressWarningsAnnotation );
|
||||
|
||||
tmp = env.getOptions().get( JPAMetaModelEntityProcessor.FULLY_ANNOTATION_CONFIGURED_OPTION );
|
||||
boolean fullyAnnotationConfigured = Boolean.parseBoolean( tmp );
|
||||
|
||||
boolean fullyAnnotationConfigured = handleSettings( processingEnvironment );
|
||||
if ( !fullyAnnotationConfigured ) {
|
||||
JpaDescriptorParser parser = new JpaDescriptorParser( context );
|
||||
parser.parseXml();
|
||||
|
@ -136,6 +115,32 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean handleSettings(ProcessingEnvironment environment) {
|
||||
final PackageElement jakartaInjectPackage =
|
||||
context.getProcessingEnvironment().getElementUtils()
|
||||
.getPackageElement( "jakarta.inject" );
|
||||
context.setAddInjectAnnotation( jakartaInjectPackage != null );
|
||||
|
||||
final Map<String, String> options = environment.getOptions();
|
||||
|
||||
String setting = options.get( ADD_GENERATED_ANNOTATION );
|
||||
if ( setting != null ) {
|
||||
context.setAddGeneratedAnnotation( parseBoolean( setting ) );
|
||||
}
|
||||
else {
|
||||
PackageElement jakartaAnnotationPackage =
|
||||
context.getProcessingEnvironment().getElementUtils()
|
||||
.getPackageElement( "jakarta.annotation" );
|
||||
context.setAddGeneratedAnnotation( jakartaAnnotationPackage != null );
|
||||
}
|
||||
|
||||
context.setAddGenerationDate(parseBoolean( options.get( ADD_GENERATION_DATE ) ) );
|
||||
|
||||
context.setAddSuppressWarningsAnnotation( parseBoolean( options.get( ADD_SUPPRESS_WARNINGS_ANNOTATION ) ) );
|
||||
|
||||
return parseBoolean( options.get( FULLY_ANNOTATION_CONFIGURED_OPTION ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
|
@ -143,19 +148,24 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
|
||||
@Override
|
||||
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnvironment) {
|
||||
// see also METAGEN-45
|
||||
if ( roundEnvironment.processingOver() || annotations.size() == 0 ) {
|
||||
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
|
||||
}
|
||||
|
||||
if ( context.isFullyXmlConfigured() ) {
|
||||
// https://hibernate.atlassian.net/browse/METAGEN-45 claims that we need
|
||||
// if ( roundEnvironment.processingOver() || annotations.size() == 0)
|
||||
// but that was back on JDK 6 and I don't see why it should be necessary
|
||||
// - in fact we want to use the last round to run the 'elementsToRedo'
|
||||
if ( roundEnvironment.processingOver() ) {
|
||||
final Set<CharSequence> elementsToRedo = context.getElementsToRedo();
|
||||
if ( !elementsToRedo.isEmpty() ) {
|
||||
context.logMessage( Diagnostic.Kind.ERROR, "Failed to generate code for " + elementsToRedo );
|
||||
}
|
||||
}
|
||||
else if ( context.isFullyXmlConfigured() ) {
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.OTHER,
|
||||
"Skipping the processing of annotations since persistence unit is purely xml configured."
|
||||
"Skipping the processing of annotations since persistence unit is purely XML configured."
|
||||
);
|
||||
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
|
||||
}
|
||||
|
||||
else {
|
||||
try {
|
||||
processClasses( roundEnvironment );
|
||||
createMetaModelClasses();
|
||||
|
@ -163,30 +173,55 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
catch (Exception e) {
|
||||
context.logMessage( Diagnostic.Kind.ERROR, "Error generating JPA metamodel:" + e.getMessage() );
|
||||
}
|
||||
|
||||
}
|
||||
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
|
||||
}
|
||||
|
||||
private void processClasses(RoundEnvironment roundEnvironment) {
|
||||
for ( CharSequence elementName : new HashSet<>( context.getElementsToRedo() ) ) {
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Redoing element: " + elementName );
|
||||
final TypeElement typeElement = context.getElementUtils().getTypeElement( elementName );
|
||||
try {
|
||||
final AnnotationMetaEntity metaEntity =
|
||||
AnnotationMetaEntity.create( typeElement, context, false );
|
||||
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
|
||||
context.removeElementToRedo( elementName );
|
||||
}
|
||||
catch (ProcessLaterException processLaterException) {
|
||||
// leave it there for next time
|
||||
}
|
||||
}
|
||||
|
||||
for ( Element element : roundEnvironment.getRootElements() ) {
|
||||
if ( isJPAEntity( element ) ) {
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element.toString() );
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element );
|
||||
handleRootElementAnnotationMirrors( element );
|
||||
}
|
||||
else if ( hasAuxiliaryAnnotations( element ) ) {
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element.toString() );
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element );
|
||||
handleRootElementAuxiliaryAnnotationMirrors( element );
|
||||
}
|
||||
else if ( element instanceof TypeElement ) {
|
||||
for ( Element enclosedElement : element.getEnclosedElements() ) {
|
||||
if ( containsAnnotation( enclosedElement, HQL, SQL ) ) {
|
||||
final TypeElement typeElement = (TypeElement) element;
|
||||
try {
|
||||
for ( Element member : typeElement.getEnclosedElements() ) {
|
||||
if ( containsAnnotation( member, HQL, SQL, FIND ) ) {
|
||||
final AnnotationMetaEntity metaEntity =
|
||||
AnnotationMetaEntity.create( (TypeElement) element, context, false );
|
||||
AnnotationMetaEntity.create( typeElement, context, false );
|
||||
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ProcessLaterException processLaterException) {
|
||||
final Name qualifiedName = typeElement.getQualifiedName();
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.OTHER,
|
||||
"Could not process: " + qualifiedName + " (will redo in next round)"
|
||||
);
|
||||
context.addElementToRedo( qualifiedName );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,8 +405,8 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
|
||||
static class ContainsAttributeTypeVisitor extends SimpleTypeVisitor8<Boolean, Element> {
|
||||
|
||||
private Context context;
|
||||
private TypeElement type;
|
||||
private final Context context;
|
||||
private final TypeElement type;
|
||||
|
||||
ContainsAttributeTypeVisitor(TypeElement elem, Context context) {
|
||||
this.context = context;
|
||||
|
|
|
@ -18,7 +18,6 @@ import javax.lang.model.element.ElementKind;
|
|||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
|
@ -144,8 +143,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
|
||||
private static String getPackageName(Context context, TypeElement element) {
|
||||
PackageElement packageOf = context.getElementUtils().getPackageOf( element );
|
||||
return context.getElementUtils().getName( packageOf.getQualifiedName() ).toString();
|
||||
return context.getElementUtils().getPackageOf( element ).getQualifiedName().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -485,7 +483,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
else {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<AnnotationValue> annotationValues = (List<AnnotationValue>) enabledFetchProfiles;
|
||||
return annotationValues.stream().map(AnnotationValue::toString).collect(toList());
|
||||
List<String> result = annotationValues.stream().map(AnnotationValue::toString).collect(toList());
|
||||
if ( result.stream().anyMatch("<error>"::equals) ) {
|
||||
throw new ProcessLaterException();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpamodelgen.annotation;
|
||||
|
||||
public class ProcessLaterException extends RuntimeException {
|
||||
}
|
|
@ -58,7 +58,7 @@ public class JpaDescriptorParser {
|
|||
|
||||
public JpaDescriptorParser(Context context) {
|
||||
this.context = context;
|
||||
this.entityMappings = new ArrayList<EntityMappings>();
|
||||
this.entityMappings = new ArrayList<>();
|
||||
this.xmlParserHelper = new XmlParserHelper( context );
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class JpaDescriptorParser {
|
|||
}
|
||||
|
||||
private Collection<String> determineMappingFileNames() {
|
||||
Collection<String> mappingFileNames = new ArrayList<String>();
|
||||
Collection<String> mappingFileNames = new ArrayList<>();
|
||||
|
||||
Persistence persistence = getPersistence();
|
||||
if ( persistence != null ) {
|
||||
|
@ -227,10 +227,7 @@ public class JpaDescriptorParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
//handled in the outer scope
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
catch (IOException|ClassNotFoundException e) {
|
||||
//handled in the outer scope
|
||||
}
|
||||
}
|
||||
|
@ -436,12 +433,7 @@ public class JpaDescriptorParser {
|
|||
for ( EntityMappings mappings : entityMappings ) {
|
||||
PersistenceUnitMetadata meta = mappings.getPersistenceUnitMetadata();
|
||||
if ( meta != null ) {
|
||||
if ( meta.getXmlMappingMetadataComplete() != null ) {
|
||||
context.mappingDocumentFullyXmlConfigured( true );
|
||||
}
|
||||
else {
|
||||
context.mappingDocumentFullyXmlConfigured( false );
|
||||
}
|
||||
context.mappingDocumentFullyXmlConfigured( meta.getXmlMappingMetadataComplete() != null );
|
||||
|
||||
PersistenceUnitDefaults persistenceUnitDefaults = meta.getPersistenceUnitDefaults();
|
||||
if ( persistenceUnitDefaults != null ) {
|
||||
|
|
Loading…
Reference in New Issue