minor bug fixes and code cleanups to Metamodel Generator
This commit is contained in:
parent
84714ed585
commit
677b9848a2
|
@ -95,34 +95,34 @@ public final class ClassWriter {
|
|||
* @return body content
|
||||
*/
|
||||
private static StringBuffer generateBody(Metamodel entity, Context context) {
|
||||
StringWriter sw = new StringWriter();
|
||||
final StringWriter sw = new StringWriter();
|
||||
try ( PrintWriter pw = new PrintWriter(sw) ) {
|
||||
|
||||
if ( entity.getElement() instanceof TypeElement ) {
|
||||
pw.println(writeStaticMetaModelAnnotation(entity));
|
||||
pw.println( writeStaticMetaModelAnnotation(entity) );
|
||||
}
|
||||
|
||||
if (context.addGeneratedAnnotation()) {
|
||||
pw.println(writeGeneratedAnnotation(entity, context));
|
||||
if ( context.addGeneratedAnnotation() ) {
|
||||
pw.println( writeGeneratedAnnotation(entity, context) );
|
||||
}
|
||||
if (context.isAddSuppressWarningsAnnotation()) {
|
||||
pw.println(writeSuppressWarnings());
|
||||
if ( context.isAddSuppressWarningsAnnotation() ) {
|
||||
pw.println( writeSuppressWarnings() );
|
||||
}
|
||||
|
||||
printClassDeclaration(entity, pw, context);
|
||||
printClassDeclaration( entity, pw, context );
|
||||
|
||||
pw.println();
|
||||
|
||||
List<MetaAttribute> members = entity.getMembers();
|
||||
for (MetaAttribute metaMember : members) {
|
||||
if (metaMember.hasTypedAttribute()) {
|
||||
final List<MetaAttribute> members = entity.getMembers();
|
||||
for ( MetaAttribute metaMember : members ) {
|
||||
if ( metaMember.hasTypedAttribute() ) {
|
||||
metaMember.getAttributeDeclarationString().lines()
|
||||
.forEach(line -> pw.println(" " + line));
|
||||
}
|
||||
}
|
||||
pw.println();
|
||||
for (MetaAttribute metaMember : members) {
|
||||
pw.println(" " + metaMember.getAttributeNameDeclarationString());
|
||||
for ( MetaAttribute metaMember : members ) {
|
||||
pw.println( " " + metaMember.getAttributeNameDeclarationString() );
|
||||
}
|
||||
|
||||
pw.println();
|
||||
|
|
|
@ -212,23 +212,19 @@ public final class Context {
|
|||
}
|
||||
|
||||
public void logMessage(Diagnostic.Kind type, String message) {
|
||||
if ( !logDebug && type.equals( Diagnostic.Kind.OTHER ) ) {
|
||||
return;
|
||||
if ( logDebug || type != Diagnostic.Kind.OTHER ) {
|
||||
pe.getMessager().printMessage( type, message );
|
||||
}
|
||||
pe.getMessager().printMessage( type, message );
|
||||
}
|
||||
|
||||
public boolean isFullyXmlConfigured() {
|
||||
return fullyXmlConfigured != null && fullyXmlConfigured.booleanValue();
|
||||
return fullyXmlConfigured != null && fullyXmlConfigured;
|
||||
}
|
||||
|
||||
public void mappingDocumentFullyXmlConfigured(boolean fullyXmlConfigured) {
|
||||
if ( this.fullyXmlConfigured == null ) {
|
||||
this.fullyXmlConfigured = fullyXmlConfigured;
|
||||
}
|
||||
else {
|
||||
this.fullyXmlConfigured = this.fullyXmlConfigured && fullyXmlConfigured;
|
||||
}
|
||||
this.fullyXmlConfigured = this.fullyXmlConfigured == null
|
||||
? fullyXmlConfigured
|
||||
: this.fullyXmlConfigured && fullyXmlConfigured;
|
||||
}
|
||||
|
||||
public AccessType getPersistenceUnitDefaultAccessType() {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.jpamodelgen;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
@ -21,13 +22,13 @@ import org.hibernate.jpamodelgen.model.ImportContext;
|
|||
*/
|
||||
public class ImportContextImpl implements ImportContext {
|
||||
|
||||
private Set<String> imports = new TreeSet<String>();
|
||||
private Set<String> staticImports = new TreeSet<String>();
|
||||
private Map<String, String> simpleNames = new HashMap<String, String>();
|
||||
private final Set<String> imports = new TreeSet<>();
|
||||
private final Set<String> staticImports = new TreeSet<>();
|
||||
private final Map<String, String> simpleNames = new HashMap<>();
|
||||
|
||||
private String basePackage = "";
|
||||
|
||||
private static final Map<String, String> PRIMITIVES = new HashMap<String, String>();
|
||||
private static final Map<String, String> PRIMITIVES = new HashMap<>();
|
||||
|
||||
static {
|
||||
PRIMITIVES.put( "char", "Character" );
|
||||
|
@ -56,61 +57,79 @@ public class ImportContextImpl implements ImportContext {
|
|||
* {@code java.util.Collection<org.marvel.Hulk>} imports {@code java.util.Collection} and returns {@code Collection}
|
||||
* {@code org.marvel.Hulk[]} imports {@code org.marvel.Hulk} and returns {@code Hulk}
|
||||
*
|
||||
* @param fqcn Fully qualified class name
|
||||
* @param typeExpression A type expression
|
||||
*
|
||||
* @return import string
|
||||
*/
|
||||
public String importType(String fqcn) {
|
||||
String result = fqcn;
|
||||
public String importType(String typeExpression) {
|
||||
String result = typeExpression;
|
||||
|
||||
//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( '[' ) );
|
||||
fqcn = result;
|
||||
}
|
||||
else if ( fqcn.endsWith( "..." ) ) {
|
||||
additionalTypePart = "...";
|
||||
result = result.substring( 0, fqcn.indexOf( "..." ) );
|
||||
fqcn = result;
|
||||
// strip off type annotations and '? super' or '? extends'
|
||||
String preamble = "";
|
||||
if ( result.startsWith("@") || result.startsWith("?") ) {
|
||||
int index = result.lastIndexOf(' ');
|
||||
if ( index > 0 ) {
|
||||
preamble = result.substring( 0, index+1 );
|
||||
result = result.substring( index+1 );
|
||||
}
|
||||
}
|
||||
|
||||
String pureFqcn = fqcn.replace( '$', '.' );
|
||||
String appendices = "";
|
||||
if ( result.indexOf( '<' ) >= 0 ) {
|
||||
int startIndex = result.indexOf('<');
|
||||
int endIndex = result.lastIndexOf('>');
|
||||
appendices = '<' + importTypes( result.substring( startIndex + 1, endIndex ) ) + '>'
|
||||
+ result.substring( endIndex + 1 );
|
||||
result = result.substring( 0, startIndex );
|
||||
}
|
||||
else if ( result.indexOf( '[' ) >= 0 ) {
|
||||
int index = result.indexOf('[');
|
||||
appendices = result.substring( index );
|
||||
result = result.substring( 0, index );
|
||||
}
|
||||
else if ( result.endsWith( "..." ) ) {
|
||||
appendices = "...";
|
||||
int index = result.indexOf("...");
|
||||
result = result.substring( 0, index );
|
||||
}
|
||||
|
||||
return ( preamble + unqualifyName( result ) + appendices )
|
||||
.replace( '$', '.' );
|
||||
}
|
||||
|
||||
private String unqualifyName(String qualifiedName) {
|
||||
final String sourceQualifiedName = qualifiedName.replace( '$', '.' );
|
||||
final String simpleName = unqualify( qualifiedName );
|
||||
boolean canBeSimple;
|
||||
|
||||
String simpleName = unqualify( fqcn );
|
||||
if ( simpleNames.containsKey( simpleName ) ) {
|
||||
String existingFqcn = simpleNames.get( simpleName );
|
||||
canBeSimple = existingFqcn.equals( pureFqcn );
|
||||
String existing = simpleNames.get( simpleName );
|
||||
canBeSimple = existing.equals( sourceQualifiedName );
|
||||
}
|
||||
else {
|
||||
canBeSimple = true;
|
||||
simpleNames.put( simpleName, pureFqcn );
|
||||
imports.add( pureFqcn );
|
||||
simpleNames.put( simpleName, sourceQualifiedName );
|
||||
imports.add( sourceQualifiedName );
|
||||
}
|
||||
|
||||
|
||||
if ( inSamePackage( fqcn ) || ( imports.contains( pureFqcn ) && canBeSimple ) ) {
|
||||
result = unqualify( result );
|
||||
if ( inSamePackage( qualifiedName ) || inJavaLang( qualifiedName )
|
||||
|| canBeSimple && imports.contains( sourceQualifiedName ) ) {
|
||||
return unqualify( qualifiedName );
|
||||
}
|
||||
else if ( inJavaLang( fqcn ) ) {
|
||||
result = result.substring( "java.lang.".length() );
|
||||
else {
|
||||
return qualifiedName;
|
||||
}
|
||||
}
|
||||
|
||||
if ( additionalTypePart != null ) {
|
||||
result = result + additionalTypePart;
|
||||
private String importTypes(String originalArgList) {
|
||||
String[] args = originalArgList.split(",");
|
||||
StringBuilder argList = new StringBuilder();
|
||||
for ( String arg : args ) {
|
||||
if ( argList.length() > 0 ) {
|
||||
argList.append(',');
|
||||
}
|
||||
argList.append( importType( arg ) );
|
||||
}
|
||||
|
||||
result = result.replace( '$', '.' );
|
||||
return result;
|
||||
return argList.toString();
|
||||
}
|
||||
|
||||
public String staticImport(String fqcn, String member) {
|
||||
|
@ -135,9 +154,7 @@ public class ImportContextImpl implements ImportContext {
|
|||
}
|
||||
|
||||
private boolean inSamePackage(String className) {
|
||||
String other = qualifier( className );
|
||||
return other == basePackage
|
||||
|| ( other != null && other.equals( basePackage ) );
|
||||
return Objects.equals( qualifier( className ), basePackage );
|
||||
}
|
||||
|
||||
private boolean inJavaLang(String className) {
|
||||
|
|
|
@ -8,7 +8,6 @@ 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;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
|
@ -26,7 +25,7 @@ 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.lang.model.util.SimpleTypeVisitor8;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
|
||||
|
@ -42,6 +41,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
import static org.hibernate.jpamodelgen.util.Constants.HQL;
|
||||
import static org.hibernate.jpamodelgen.util.Constants.SQL;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.isAnnotationMirrorOfType;
|
||||
|
||||
/**
|
||||
* Main annotation processor.
|
||||
|
@ -149,8 +149,19 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
|
||||
}
|
||||
|
||||
Set<? extends Element> elements = roundEnvironment.getRootElements();
|
||||
for ( Element element : elements ) {
|
||||
try {
|
||||
processClasses( roundEnvironment );
|
||||
createMetaModelClasses();
|
||||
}
|
||||
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 ( Element element : roundEnvironment.getRootElements() ) {
|
||||
if ( isJPAEntity( element ) ) {
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class " + element.toString() );
|
||||
handleRootElementAnnotationMirrors( element );
|
||||
|
@ -162,7 +173,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
else if ( element instanceof TypeElement ) {
|
||||
for ( Element enclosedElement : element.getEnclosedElements() ) {
|
||||
if ( containsAnnotation( enclosedElement, HQL, SQL ) ) {
|
||||
AnnotationMetaEntity metaEntity =
|
||||
final AnnotationMetaEntity metaEntity =
|
||||
AnnotationMetaEntity.create( (TypeElement) element, context, false );
|
||||
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
|
||||
break;
|
||||
|
@ -170,9 +181,6 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
createMetaModelClasses();
|
||||
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
|
||||
}
|
||||
|
||||
private void createMetaModelClasses() {
|
||||
|
@ -197,9 +205,9 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
|
||||
// we cannot process the delayed entities in any order. There might be dependencies between them.
|
||||
// we need to process the top level entities first
|
||||
Collection<Metamodel> toProcessEntities = context.getMetaEmbeddables();
|
||||
final Collection<Metamodel> toProcessEntities = context.getMetaEmbeddables();
|
||||
while ( !toProcessEntities.isEmpty() ) {
|
||||
Set<Metamodel> processedEntities = new HashSet<Metamodel>();
|
||||
final Set<Metamodel> processedEntities = new HashSet<>();
|
||||
int toProcessCountBeforeLoop = toProcessEntities.size();
|
||||
for ( Metamodel entity : toProcessEntities ) {
|
||||
// see METAGEN-36
|
||||
|
@ -227,7 +235,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
}
|
||||
|
||||
private boolean modelGenerationNeedsToBeDeferred(Collection<Metamodel> entities, Metamodel containedEntity) {
|
||||
Element element = containedEntity.getElement();
|
||||
final Element element = containedEntity.getElement();
|
||||
if ( element instanceof TypeElement ) {
|
||||
ContainsAttributeTypeVisitor visitor = new ContainsAttributeTypeVisitor( (TypeElement) element, context );
|
||||
for ( Metamodel entity : entities ) {
|
||||
|
@ -236,22 +244,18 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
}
|
||||
for ( Element subElement : ElementFilter.fieldsIn( entity.getElement().getEnclosedElements() ) ) {
|
||||
TypeMirror mirror = subElement.asType();
|
||||
if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) {
|
||||
continue;
|
||||
}
|
||||
boolean contains = mirror.accept( visitor, subElement );
|
||||
if ( contains ) {
|
||||
return true;
|
||||
if ( TypeKind.DECLARED == mirror.getKind() ) {
|
||||
if ( mirror.accept( visitor, subElement ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( Element subElement : ElementFilter.methodsIn( entity.getElement().getEnclosedElements() ) ) {
|
||||
TypeMirror mirror = subElement.asType();
|
||||
if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) {
|
||||
continue;
|
||||
}
|
||||
boolean contains = mirror.accept( visitor, subElement );
|
||||
if ( contains ) {
|
||||
return true;
|
||||
if ( TypeKind.DECLARED == mirror.getKind() ) {
|
||||
if ( mirror.accept( visitor, subElement ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,33 +295,30 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
}
|
||||
|
||||
private void handleRootElementAnnotationMirrors(final Element element) {
|
||||
List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
|
||||
for ( AnnotationMirror mirror : annotationMirrors ) {
|
||||
if ( !element.getKind().isClass() || ElementKind.ENUM.equals( element.getKind() ) ) {
|
||||
continue;
|
||||
}
|
||||
for ( AnnotationMirror mirror : element.getAnnotationMirrors() ) {
|
||||
if ( element.getKind() == ElementKind.CLASS ) {
|
||||
final String fqn = ( (TypeElement) element ).getQualifiedName().toString();
|
||||
final Metamodel 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 );
|
||||
}
|
||||
else {
|
||||
boolean requiresLazyMemberInitialization = false;
|
||||
AnnotationMetaEntity metaEntity;
|
||||
if ( containsAnnotation( element, Constants.EMBEDDABLE ) ||
|
||||
containsAnnotation( element, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
requiresLazyMemberInitialization = true;
|
||||
}
|
||||
|
||||
String fqn = ( (TypeElement) element ).getQualifiedName().toString();
|
||||
Metamodel 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;
|
||||
}
|
||||
metaEntity = AnnotationMetaEntity.create( (TypeElement) element, context, requiresLazyMemberInitialization );
|
||||
|
||||
boolean requiresLazyMemberInitialization = false;
|
||||
AnnotationMetaEntity metaEntity;
|
||||
if ( containsAnnotation( element, Constants.EMBEDDABLE ) ||
|
||||
containsAnnotation( element, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
requiresLazyMemberInitialization = true;
|
||||
if ( alreadyExistingMetaEntity != null ) {
|
||||
metaEntity.mergeInMembers( alreadyExistingMetaEntity );
|
||||
}
|
||||
addMetaEntityToContext( mirror, metaEntity );
|
||||
}
|
||||
}
|
||||
|
||||
metaEntity = AnnotationMetaEntity.create( (TypeElement) element, context, requiresLazyMemberInitialization );
|
||||
|
||||
if ( alreadyExistingMetaEntity != null ) {
|
||||
metaEntity.mergeInMembers( alreadyExistingMetaEntity );
|
||||
}
|
||||
addMetaEntityToContext( mirror, metaEntity );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,30 +338,30 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
|||
|
||||
private @Nullable Metamodel tryGettingExistingEntityFromContext(AnnotationMirror mirror, String fqn) {
|
||||
Metamodel alreadyExistingMetaEntity = null;
|
||||
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ENTITY )
|
||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
if ( isAnnotationMirrorOfType( mirror, Constants.ENTITY )
|
||||
|| isAnnotationMirrorOfType( mirror, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
alreadyExistingMetaEntity = context.getMetaEntity( fqn );
|
||||
}
|
||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.EMBEDDABLE ) ) {
|
||||
else if ( isAnnotationMirrorOfType( mirror, Constants.EMBEDDABLE ) ) {
|
||||
alreadyExistingMetaEntity = context.getMetaEmbeddable( fqn );
|
||||
}
|
||||
return alreadyExistingMetaEntity;
|
||||
}
|
||||
|
||||
private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) {
|
||||
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ENTITY ) ) {
|
||||
if ( isAnnotationMirrorOfType( mirror, Constants.ENTITY ) ) {
|
||||
context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity );
|
||||
}
|
||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
else if ( isAnnotationMirrorOfType( mirror, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity );
|
||||
}
|
||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.EMBEDDABLE ) ) {
|
||||
else if ( isAnnotationMirrorOfType( mirror, Constants.EMBEDDABLE ) ) {
|
||||
context.addMetaEmbeddable( metaEntity.getQualifiedName(), metaEntity );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ContainsAttributeTypeVisitor extends SimpleTypeVisitor6<Boolean, Element> {
|
||||
static class ContainsAttributeTypeVisitor extends SimpleTypeVisitor8<Boolean, Element> {
|
||||
|
||||
private Context context;
|
||||
private TypeElement type;
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.jpamodelgen.annotation;
|
|||
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
||||
import org.hibernate.jpamodelgen.model.Metamodel;
|
||||
import org.hibernate.jpamodelgen.util.Constants;
|
||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||
import org.hibernate.jpamodelgen.validation.ProcessorSessionFactory;
|
||||
import org.hibernate.jpamodelgen.validation.Validation;
|
||||
|
||||
|
@ -17,6 +16,8 @@ import javax.lang.model.element.AnnotationMirror;
|
|||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror;
|
||||
|
||||
public abstract class AnnotationMeta implements Metamodel {
|
||||
|
||||
|
@ -41,47 +42,45 @@ public abstract class AnnotationMeta implements Metamodel {
|
|||
}
|
||||
|
||||
void checkNamedQueries() {
|
||||
if ( TypeUtils.containsAnnotation( getElement(), Constants.CHECK_HQL )
|
||||
|| TypeUtils.containsAnnotation( getElement().getEnclosingElement(), Constants.CHECK_HQL ) ) {
|
||||
checkNamedQueriesForAnnotation( Constants.NAMED_QUERY );
|
||||
checkNamedQueriesForRepeatableAnnotation( Constants.NAMED_QUERIES );
|
||||
checkNamedQueriesForAnnotation( Constants.HIB_NAMED_QUERY );
|
||||
checkNamedQueriesForRepeatableAnnotation( Constants.HIB_NAMED_QUERIES );
|
||||
}
|
||||
|
||||
boolean checkHql = containsAnnotation( getElement(), Constants.CHECK_HQL )
|
||||
|| containsAnnotation( getElement().getEnclosingElement(), Constants.CHECK_HQL );
|
||||
checkNamedQueriesForAnnotation( Constants.NAMED_QUERY, checkHql );
|
||||
checkNamedQueriesForRepeatableAnnotation( Constants.NAMED_QUERIES, checkHql );
|
||||
checkNamedQueriesForAnnotation( Constants.HIB_NAMED_QUERY, checkHql );
|
||||
checkNamedQueriesForRepeatableAnnotation( Constants.HIB_NAMED_QUERIES, checkHql );
|
||||
}
|
||||
|
||||
private void checkNamedQueriesForAnnotation(String annotationName) {
|
||||
AnnotationMirror mirror = TypeUtils.getAnnotationMirror(getElement(), annotationName);
|
||||
private void checkNamedQueriesForAnnotation(String annotationName, boolean checkHql) {
|
||||
final AnnotationMirror mirror = getAnnotationMirror( getElement(), annotationName );
|
||||
if ( mirror != null ) {
|
||||
checkNamedQueriesForMirror( mirror );
|
||||
checkNamedQueriesForMirror( mirror, checkHql );
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNamedQueriesForRepeatableAnnotation(String annotationName) {
|
||||
AnnotationMirror mirror = TypeUtils.getAnnotationMirror(getElement(), annotationName);
|
||||
private void checkNamedQueriesForRepeatableAnnotation(String annotationName, boolean checkHql) {
|
||||
final AnnotationMirror mirror = getAnnotationMirror( getElement(), annotationName );
|
||||
if ( mirror != null ) {
|
||||
mirror.getElementValues().forEach((key, value) -> {
|
||||
if ( key.getSimpleName().contentEquals("value") ) {
|
||||
List<? extends AnnotationMirror> values =
|
||||
(List<? extends AnnotationMirror>) value.getValue();
|
||||
for ( AnnotationMirror annotationMirror : values ) {
|
||||
checkNamedQueriesForMirror( annotationMirror );
|
||||
checkNamedQueriesForMirror( annotationMirror, checkHql );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNamedQueriesForMirror(AnnotationMirror mirror) {
|
||||
private void checkNamedQueriesForMirror(AnnotationMirror mirror, boolean checkHql) {
|
||||
mirror.getElementValues().forEach((key, value) -> {
|
||||
if ( key.getSimpleName().contentEquals("query") ) {
|
||||
String hql = value.getValue().toString();
|
||||
final String hql = value.getValue().toString();
|
||||
Validation.validate(
|
||||
hql,
|
||||
false,
|
||||
false, checkHql,
|
||||
emptySet(), emptySet(),
|
||||
new ErrorHandler( getElement(), mirror, hql, getContext()),
|
||||
new ErrorHandler( getElement(), mirror, hql, getContext() ),
|
||||
ProcessorSessionFactory.create( getContext().getProcessingEnvironment() )
|
||||
);
|
||||
}
|
||||
|
@ -89,7 +88,7 @@ public abstract class AnnotationMeta implements Metamodel {
|
|||
}
|
||||
|
||||
private void addAuxiliaryMembersForRepeatableAnnotation(String annotationName, String prefix) {
|
||||
AnnotationMirror mirror = TypeUtils.getAnnotationMirror( getElement(), annotationName );
|
||||
final AnnotationMirror mirror = getAnnotationMirror( getElement(), annotationName );
|
||||
if ( mirror != null ) {
|
||||
mirror.getElementValues().forEach((key, value) -> {
|
||||
if ( key.getSimpleName().contentEquals("value") ) {
|
||||
|
@ -104,7 +103,7 @@ public abstract class AnnotationMeta implements Metamodel {
|
|||
}
|
||||
|
||||
private void addAuxiliaryMembersForAnnotation(String annotationName, String prefix) {
|
||||
AnnotationMirror mirror = TypeUtils.getAnnotationMirror( getElement(), annotationName);
|
||||
final AnnotationMirror mirror = getAnnotationMirror( getElement(), annotationName );
|
||||
if ( mirror != null ) {
|
||||
addAuxiliaryMembersForMirror( mirror, prefix );
|
||||
}
|
||||
|
@ -113,8 +112,9 @@ public abstract class AnnotationMeta implements Metamodel {
|
|||
private void addAuxiliaryMembersForMirror(AnnotationMirror mirror, String prefix) {
|
||||
mirror.getElementValues().forEach((key, value) -> {
|
||||
if ( key.getSimpleName().contentEquals("name") ) {
|
||||
String name = value.getValue().toString();
|
||||
putMember( prefix + name, new NameMetaAttribute( this, name, prefix ) );
|
||||
final String name = value.getValue().toString();
|
||||
putMember( prefix + name,
|
||||
new NameMetaAttribute( this, name, prefix ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ import org.hibernate.jpamodelgen.util.StringUtil;
|
|||
*/
|
||||
public abstract class AnnotationMetaAttribute implements MetaAttribute {
|
||||
|
||||
private final Element element;
|
||||
private final AnnotationMetaEntity parent;
|
||||
final Element element;
|
||||
final AnnotationMetaEntity parent;
|
||||
private final String type;
|
||||
|
||||
public AnnotationMetaAttribute(AnnotationMetaEntity parent, Element element, String type) {
|
||||
|
@ -43,10 +43,10 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
|
|||
public String getAttributeDeclarationString() {
|
||||
return new StringBuilder()
|
||||
.append("\n/**\n * @see ")
|
||||
.append(parent.getQualifiedName())
|
||||
.append("#")
|
||||
.append(element.getSimpleName())
|
||||
.append("\n **/\n")
|
||||
.append( parent.getQualifiedName() )
|
||||
.append( "#")
|
||||
.append( element.getSimpleName() )
|
||||
.append( "\n **/\n" )
|
||||
.append( "public static volatile " )
|
||||
.append( parent.importType( getMetaType() ) )
|
||||
.append( "<" )
|
||||
|
@ -61,7 +61,8 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
|
|||
|
||||
@Override
|
||||
public String getAttributeNameDeclarationString(){
|
||||
return new StringBuilder().append("public static final ")
|
||||
return new StringBuilder()
|
||||
.append("public static final ")
|
||||
.append(parent.importType(String.class.getName()))
|
||||
.append(" ")
|
||||
.append(StringUtil.getUpperUnderscoreCaseFromLowerCamelCase(getPropertyName()))
|
||||
|
@ -109,11 +110,10 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
|
|||
|
||||
@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();
|
||||
return new StringBuilder()
|
||||
.append( "AnnotationMetaAttribute" )
|
||||
.append( "{element=" ).append( element )
|
||||
.append( ", type='" ).append( type ).append( '\'' )
|
||||
.append( '}' ).toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,12 @@ import javax.lang.model.element.AnnotationMirror;
|
|||
import javax.lang.model.element.Element;
|
||||
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.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.tools.Diagnostic;
|
||||
|
@ -32,8 +34,6 @@ import org.hibernate.jpamodelgen.model.Metamodel;
|
|||
import org.hibernate.jpamodelgen.util.AccessType;
|
||||
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
||||
import org.hibernate.jpamodelgen.util.Constants;
|
||||
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||
import org.hibernate.jpamodelgen.validation.ProcessorSessionFactory;
|
||||
import org.hibernate.jpamodelgen.validation.Validation;
|
||||
|
||||
|
@ -41,7 +41,9 @@ import static java.util.Collections.emptySet;
|
|||
import static java.util.stream.Collectors.toList;
|
||||
import static org.hibernate.jpamodelgen.annotation.QueryMethod.isOrderParam;
|
||||
import static org.hibernate.jpamodelgen.annotation.QueryMethod.isPageParam;
|
||||
import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAccessTypeForHierarchy;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAnnotationSpecifiedAccessType;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValue;
|
||||
|
@ -191,28 +193,26 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "AnnotationMetaEntity" );
|
||||
sb.append( "{element=" ).append( element );
|
||||
sb.append( ", members=" ).append( members );
|
||||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
return new StringBuilder()
|
||||
.append( "AnnotationMetaEntity" )
|
||||
.append( "{element=" )
|
||||
.append( element )
|
||||
.append( ", members=" )
|
||||
.append( members )
|
||||
.append( '}' )
|
||||
.toString();
|
||||
}
|
||||
|
||||
protected final void init() {
|
||||
getContext().logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
||||
|
||||
TypeUtils.determineAccessTypeForHierarchy( element, context );
|
||||
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
||||
entityAccessTypeInfo = NullnessUtil.castNonNull( accessTypeInfo );
|
||||
|
||||
List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() );
|
||||
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
||||
|
||||
List<? extends Element> methodsOfClass = ElementFilter.methodsIn( element.getEnclosedElements() );
|
||||
List<Element> gettersAndSettersOfClass = new ArrayList<>();
|
||||
List<ExecutableElement> queryMethods = new ArrayList<>();
|
||||
determineAccessTypeForHierarchy( element, context );
|
||||
entityAccessTypeInfo = castNonNull( context.getAccessTypeInfo( getQualifiedName() ) );
|
||||
|
||||
final List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() );
|
||||
final List<? extends Element> methodsOfClass = ElementFilter.methodsIn( element.getEnclosedElements() );
|
||||
final List<Element> gettersAndSettersOfClass = new ArrayList<>();
|
||||
final List<ExecutableElement> queryMethods = new ArrayList<>();
|
||||
for ( Element rawMethodOfClass: methodsOfClass ) {
|
||||
if ( isGetterOrSetter( rawMethodOfClass ) ) {
|
||||
gettersAndSettersOfClass.add( rawMethodOfClass );
|
||||
|
@ -222,6 +222,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
queryMethods.add( (ExecutableElement) rawMethodOfClass );
|
||||
}
|
||||
}
|
||||
|
||||
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
||||
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );
|
||||
|
||||
addAuxiliaryMembers();
|
||||
|
@ -241,48 +243,48 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
* @return whether method respects Java Bean conventions.
|
||||
*/
|
||||
private boolean isGetterOrSetter(Element methodOfClass) {
|
||||
ExecutableType methodType = (ExecutableType) methodOfClass.asType();
|
||||
String methodSimpleName = methodOfClass.getSimpleName().toString();
|
||||
List<? extends TypeMirror> methodParameterTypes = methodType.getParameterTypes();
|
||||
TypeMirror returnType = methodType.getReturnType();
|
||||
|
||||
return isSetter(methodSimpleName, methodParameterTypes, returnType)
|
||||
|| isGetter(methodSimpleName, methodParameterTypes, returnType);
|
||||
final ExecutableType methodType = (ExecutableType) methodOfClass.asType();
|
||||
final Name methodSimpleName = methodOfClass.getSimpleName();
|
||||
final List<? extends TypeMirror> methodParameterTypes = methodType.getParameterTypes();
|
||||
final TypeMirror returnType = methodType.getReturnType();
|
||||
return isSetter( methodSimpleName, methodParameterTypes, returnType )
|
||||
|| isGetter( methodSimpleName, methodParameterTypes, returnType );
|
||||
}
|
||||
|
||||
private static boolean isGetter(String methodSimpleName, List<? extends TypeMirror> methodParameterTypes, TypeMirror returnType) {
|
||||
return (methodSimpleName.startsWith("get") || methodSimpleName.startsWith("is"))
|
||||
private static boolean isGetter(Name methodSimpleName, List<? extends TypeMirror> methodParameterTypes, TypeMirror returnType) {
|
||||
return ( methodSimpleName.subSequence(0,3).toString().equals("get")
|
||||
|| methodSimpleName.subSequence(0,2).toString().equals("is") )
|
||||
&& methodParameterTypes.isEmpty()
|
||||
&& !"void".equalsIgnoreCase(returnType.toString());
|
||||
&& returnType.getKind() != TypeKind.VOID;
|
||||
}
|
||||
|
||||
private static boolean isSetter(String methodSimpleName, List<? extends TypeMirror> methodParameterTypes, TypeMirror returnType) {
|
||||
return methodSimpleName.startsWith("set")
|
||||
private static boolean isSetter(Name methodSimpleName, List<? extends TypeMirror> methodParameterTypes, TypeMirror returnType) {
|
||||
return methodSimpleName.subSequence(0,3).toString().equals("set")
|
||||
&& methodParameterTypes.size() == 1
|
||||
&& "void".equalsIgnoreCase(returnType.toString());
|
||||
&& returnType.getKind() != TypeKind.VOID;
|
||||
}
|
||||
|
||||
private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) {
|
||||
for ( Element memberOfClass : membersOfClass ) {
|
||||
AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( memberOfClass );
|
||||
if ( entityAccessTypeInfo.getAccessType() != membersKind && forcedAccessType == null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( containsAnnotation( memberOfClass, Constants.TRANSIENT )
|
||||
|| memberOfClass.getModifiers().contains( Modifier.TRANSIENT )
|
||||
|| memberOfClass.getModifiers().contains( Modifier.STATIC ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MetaAttributeGenerationVisitor visitor = new MetaAttributeGenerationVisitor( this, context );
|
||||
AnnotationMetaAttribute result = memberOfClass.asType().accept( visitor, memberOfClass );
|
||||
if ( result != null ) {
|
||||
members.put( result.getPropertyName(), result );
|
||||
if ( isPersistent( memberOfClass, membersKind ) ) {
|
||||
final AnnotationMetaAttribute result =
|
||||
memberOfClass.asType()
|
||||
.accept( new MetaAttributeGenerationVisitor(this, context ), memberOfClass );
|
||||
if ( result != null ) {
|
||||
members.put( result.getPropertyName(), result );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPersistent(Element memberOfClass, AccessType membersKind) {
|
||||
return ( entityAccessTypeInfo.getAccessType() == membersKind
|
||||
|| determineAnnotationSpecifiedAccessType( memberOfClass ) != null )
|
||||
&& !containsAnnotation( memberOfClass, Constants.TRANSIENT )
|
||||
&& !memberOfClass.getModifiers().contains( Modifier.TRANSIENT )
|
||||
&& !memberOfClass.getModifiers().contains( Modifier.STATIC );
|
||||
}
|
||||
|
||||
private void addQueryMethods(List<ExecutableElement> queryMethods) {
|
||||
for ( ExecutableElement method : queryMethods) {
|
||||
addQueryMethod( method );
|
||||
|
@ -317,11 +319,15 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
addQueryMethod( method, methodName, returnTypeName, containerTypeName );
|
||||
}
|
||||
else {
|
||||
context.message( method, "incorrect return type '" + containerTypeName + "'", Diagnostic.Kind.ERROR );
|
||||
context.message( method,
|
||||
"incorrect return type '" + containerTypeName + "'",
|
||||
Diagnostic.Kind.ERROR );
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.message( method, "incorrect return type '" + declaredType + "'", Diagnostic.Kind.ERROR );
|
||||
context.message( method,
|
||||
"incorrect return type '" + declaredType + "'",
|
||||
Diagnostic.Kind.ERROR );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -392,9 +398,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
// checkHqlSyntax( method, mirror, hql );
|
||||
Validation.validate(
|
||||
hql,
|
||||
false,
|
||||
false, true,
|
||||
emptySet(), emptySet(),
|
||||
new ErrorHandler( method, mirror, hql, context),
|
||||
new ErrorHandler( method, mirror, hql, context ),
|
||||
ProcessorSessionFactory.create( context.getProcessingEnvironment() )
|
||||
);
|
||||
}
|
||||
|
@ -404,15 +410,21 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
private void checkParameters(ExecutableElement method, List<String> paramNames, List<String> paramTypes, AnnotationMirror mirror, String hql) {
|
||||
for (int i = 1; i <= paramNames.size(); i++) {
|
||||
final String param = paramNames.get(i-1);
|
||||
final String ptype = paramTypes.get(i-1);
|
||||
if ( !hql.contains(":" + param) && !hql.contains("?" + i)
|
||||
&& !isPageParam(ptype) && !isOrderParam(ptype)) {
|
||||
final String type = paramTypes.get(i-1);
|
||||
if ( parameterIsMissing( hql, i, param, type ) ) {
|
||||
context.message( method, mirror, "missing query parameter for '" + param
|
||||
+ "' (no parameter named :" + param + " or ?" + i + ")", Diagnostic.Kind.ERROR );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean parameterIsMissing(String hql, int i, String param, String type) {
|
||||
return !hql.contains(":" + param)
|
||||
&& !hql.contains("?" + i)
|
||||
&& !isPageParam(type)
|
||||
&& !isOrderParam(type);
|
||||
}
|
||||
|
||||
// private void checkHqlSyntax(ExecutableElement method, AnnotationMirror mirror, String queryString) {
|
||||
// final ANTLRErrorListener errorListener = new ErrorHandler( method, mirror, queryString );
|
||||
// final HqlLexer hqlLexer = HqlParseTreeBuilder.INSTANCE.buildHqlLexer( queryString );
|
||||
|
|
|
@ -25,10 +25,23 @@ public class AnnotationMetaMap extends AnnotationMetaCollection {
|
|||
|
||||
@Override
|
||||
public String getAttributeDeclarationString() {
|
||||
return "public static volatile " + getHostingEntity().importType( getMetaType() )
|
||||
+ "<" + getHostingEntity().importType( getHostingEntity().getQualifiedName() )
|
||||
+ ", " + getHostingEntity().importType( keyType ) + ", "
|
||||
+ getHostingEntity().importType( getTypeDeclaration() ) + "> "
|
||||
+ getPropertyName() + ";";
|
||||
return new StringBuilder()
|
||||
.append("\n/**\n * @see ")
|
||||
.append( parent.getQualifiedName() )
|
||||
.append("#")
|
||||
.append( element.getSimpleName() )
|
||||
.append("\n **/\n")
|
||||
.append("public static volatile ")
|
||||
.append( parent.importType( getMetaType() ) )
|
||||
.append("<")
|
||||
.append( parent.importType( parent.getQualifiedName() ) )
|
||||
.append(", ")
|
||||
.append( parent.importType(keyType) )
|
||||
.append(", ")
|
||||
.append( parent.importType( getTypeDeclaration() ) )
|
||||
.append("> ")
|
||||
.append( getPropertyName() )
|
||||
.append(";")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,11 +106,12 @@ public class AnnotationMetaPackage extends AnnotationMeta {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "AnnotationMetaPackage" );
|
||||
sb.append( "{element=" ).append( element );
|
||||
sb.append( '}' );
|
||||
return sb.toString();
|
||||
return new StringBuilder()
|
||||
.append( "AnnotationMetaPackage" )
|
||||
.append( "{element=" )
|
||||
.append( element )
|
||||
.append( '}' )
|
||||
.toString();
|
||||
}
|
||||
|
||||
protected final void init() {
|
||||
|
|
|
@ -18,23 +18,33 @@ import javax.lang.model.type.PrimitiveType;
|
|||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.TypeVariable;
|
||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||
import javax.lang.model.util.SimpleTypeVisitor8;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.Context;
|
||||
import org.hibernate.jpamodelgen.util.AccessType;
|
||||
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
||||
import org.hibernate.jpamodelgen.util.Constants;
|
||||
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||
import org.hibernate.jpamodelgen.util.StringUtil;
|
||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull;
|
||||
import static org.hibernate.jpamodelgen.util.StringUtil.isProperty;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAnnotationSpecifiedAccessType;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.extractClosestRealTypeAsString;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValue;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getCollectionElementType;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.getKeyType;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.isAnnotationMirrorOfType;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.toArrayTypeString;
|
||||
import static org.hibernate.jpamodelgen.util.TypeUtils.toTypeString;
|
||||
|
||||
/**
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<@Nullable AnnotationMetaAttribute, Element> {
|
||||
public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor8<@Nullable AnnotationMetaAttribute, Element> {
|
||||
|
||||
/**
|
||||
* FQCN of the Hibernate-specific {@code @Target} annotation.
|
||||
|
@ -58,7 +68,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<@Nullable
|
|||
|
||||
@Override
|
||||
public @Nullable AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) {
|
||||
return new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
||||
return new AnnotationMetaSingleAttribute( entity, element, toTypeString( t ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,167 +90,150 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<@Nullable
|
|||
// }
|
||||
// }
|
||||
// return attribute;
|
||||
return new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toArrayTypeString( t, context ) );
|
||||
return new AnnotationMetaSingleAttribute( entity, element, toArrayTypeString( t, context ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable AnnotationMetaAttribute visitTypeVariable(TypeVariable t, Element element) {
|
||||
// METAGEN-29 - for a type variable we use the upper bound
|
||||
TypeMirror mirror = t.getUpperBound();
|
||||
TypeMirror erasedType = context.getTypeUtils().erasure( mirror );
|
||||
return new AnnotationMetaSingleAttribute(
|
||||
entity, element, erasedType.toString()
|
||||
);
|
||||
final TypeMirror erasedType = context.getTypeUtils().erasure( t.getUpperBound() );
|
||||
return new AnnotationMetaSingleAttribute( entity, element, erasedType.toString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) {
|
||||
AnnotationMetaAttribute metaAttribute = null;
|
||||
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
||||
final 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() );
|
||||
final String fqNameOfReturnType = returnedElement.getQualifiedName().toString();
|
||||
final String collection = Constants.COLLECTIONS.get( fqNameOfReturnType );
|
||||
final String targetEntity = getTargetEntity( element.getAnnotationMirrors() );
|
||||
if ( collection != null ) {
|
||||
return createMetaCollectionAttribute(
|
||||
declaredType, element, fqNameOfReturnType, collection, targetEntity
|
||||
);
|
||||
return createMetaCollectionAttribute( declaredType, element, fqNameOfReturnType, collection, targetEntity );
|
||||
}
|
||||
else if ( isBasicAttribute( element, returnedElement ) ) {
|
||||
String type = targetEntity != null ? targetEntity : returnedElement.getQualifiedName().toString();
|
||||
final String type = targetEntity != null ? targetEntity : returnedElement.getQualifiedName().toString();
|
||||
return new AnnotationMetaSingleAttribute( entity, element, type );
|
||||
}
|
||||
return metaAttribute;
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable AnnotationMetaAttribute createMetaCollectionAttribute(DeclaredType declaredType, Element element, String fqNameOfReturnType, String collection, @Nullable String targetEntity) {
|
||||
if ( TypeUtils.containsAnnotation( element, Constants.ELEMENT_COLLECTION ) ) {
|
||||
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(
|
||||
collectionElementType.toString() );
|
||||
if ( accessTypeInfo == null ) {
|
||||
AccessType explicitAccessType = null;
|
||||
if ( collectionElement != null ) {
|
||||
explicitAccessType = TypeUtils.determineAnnotationSpecifiedAccessType(
|
||||
collectionElement
|
||||
);
|
||||
}
|
||||
accessTypeInfo = new AccessTypeInformation(
|
||||
collectionElementType.toString(),
|
||||
explicitAccessType,
|
||||
entity.getEntityAccessTypeInfo().getAccessType()
|
||||
private AnnotationMetaAttribute createMetaCollectionAttribute(
|
||||
DeclaredType declaredType, Element element, String fqNameOfReturnType, String collection,
|
||||
@Nullable String targetEntity) {
|
||||
if ( containsAnnotation( element, Constants.ELEMENT_COLLECTION ) ) {
|
||||
final String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() );
|
||||
final TypeMirror collectionElementType =
|
||||
getCollectionElementType( declaredType, fqNameOfReturnType, explicitTargetEntity, context );
|
||||
if ( collectionElementType.getKind() == TypeKind.DECLARED ) {
|
||||
final TypeElement collectionElement = (TypeElement)
|
||||
context.getTypeUtils().asElement( collectionElementType );
|
||||
setAccessType( collectionElementType, collectionElement );
|
||||
}
|
||||
}
|
||||
return createMetaAttribute( declaredType, element, collection, targetEntity );
|
||||
}
|
||||
|
||||
private AnnotationMetaAttribute createMetaAttribute(
|
||||
DeclaredType declaredType, Element element, String collection, @Nullable String targetEntity) {
|
||||
if ( containsAnnotation( element,
|
||||
Constants.ONE_TO_MANY, Constants.MANY_TO_MANY,
|
||||
Constants.MANY_TO_ANY, Constants.ELEMENT_COLLECTION ) ) {
|
||||
if ( collection.equals( Constants.MAP_ATTRIBUTE ) ) { //TODO: pretty fragile!
|
||||
return new AnnotationMetaMap(
|
||||
entity,
|
||||
element,
|
||||
collection,
|
||||
getMapKeyType( declaredType, element ),
|
||||
getElementType( declaredType, targetEntity )
|
||||
);
|
||||
context.addAccessTypeInformation( collectionElementType.toString(), accessTypeInfo );
|
||||
}
|
||||
else {
|
||||
accessTypeInfo.setDefaultAccessType( entity.getEntityAccessTypeInfo().getAccessType() );
|
||||
return new AnnotationMetaCollection(
|
||||
entity,
|
||||
element,
|
||||
collection,
|
||||
getElementType( declaredType, targetEntity )
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( TypeUtils.containsAnnotation(
|
||||
element,
|
||||
Constants.BASIC,
|
||||
Constants.CONVERT,
|
||||
Constants.HIBERNATE_TYPE
|
||||
) && !TypeUtils.containsAnnotation(
|
||||
element,
|
||||
Constants.ONE_TO_MANY,
|
||||
Constants.MANY_TO_MANY,
|
||||
Constants.ELEMENT_COLLECTION
|
||||
) ) {
|
||||
return new AnnotationMetaSingleAttribute(
|
||||
entity,
|
||||
element,
|
||||
TypeUtils.toTypeString( declaredType )
|
||||
else {
|
||||
final String typeWithVariablesErased = extractClosestRealTypeAsString( declaredType, context );
|
||||
return new AnnotationMetaSingleAttribute( entity, element, typeWithVariablesErased );
|
||||
}
|
||||
}
|
||||
|
||||
private void setAccessType(TypeMirror collectionElementType, TypeElement collectionElement) {
|
||||
final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( collectionElementType.toString() );
|
||||
if ( accessTypeInfo == null ) {
|
||||
final AccessTypeInformation newAccessTypeInfo = new AccessTypeInformation(
|
||||
collectionElementType.toString(),
|
||||
collectionElement == null ? null : determineAnnotationSpecifiedAccessType( collectionElement ),
|
||||
entity.getEntityAccessTypeInfo().getAccessType()
|
||||
);
|
||||
context.addAccessTypeInformation( collectionElementType.toString(), newAccessTypeInfo );
|
||||
}
|
||||
if ( collection.equals( Constants.MAP_ATTRIBUTE ) ) {
|
||||
return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity );
|
||||
else {
|
||||
accessTypeInfo.setDefaultAccessType( entity.getEntityAccessTypeInfo().getAccessType() );
|
||||
}
|
||||
return new AnnotationMetaCollection(
|
||||
entity, element, collection, getElementType( declaredType, targetEntity )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) {
|
||||
if ( !p.getKind().equals( ElementKind.METHOD ) ) {
|
||||
if ( p.getKind() == ElementKind.METHOD
|
||||
&& isProperty( p.getSimpleName().toString(), toTypeString( t.getReturnType() ) ) ) {
|
||||
return t.getReturnType().accept( this, p );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
String string = p.getSimpleName().toString();
|
||||
if ( !StringUtil.isProperty( string, TypeUtils.toTypeString( t.getReturnType() ) ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeMirror returnType = t.getReturnType();
|
||||
return returnType.accept( this, p );
|
||||
}
|
||||
|
||||
private boolean isBasicAttribute(Element element, Element returnedElement) {
|
||||
if ( TypeUtils.containsAnnotation( element, Constants.BASIC )
|
||||
|| TypeUtils.containsAnnotation( element, Constants.ONE_TO_ONE )
|
||||
|| TypeUtils.containsAnnotation( element, Constants.MANY_TO_ONE )
|
||||
|| TypeUtils.containsAnnotation( element, Constants.EMBEDDED_ID )
|
||||
|| TypeUtils.containsAnnotation( element, Constants.ID ) ) {
|
||||
if ( containsAnnotation( element, Constants.BASIC )
|
||||
|| containsAnnotation( element, Constants.ONE_TO_ONE )
|
||||
|| containsAnnotation( element, Constants.MANY_TO_ONE )
|
||||
|| containsAnnotation( element, Constants.EMBEDDED_ID )
|
||||
|| containsAnnotation( element, Constants.ID ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// METAGEN-28
|
||||
if ( TypeUtils.getAnnotationMirror( element, ORG_HIBERNATE_ANNOTATIONS_TYPE ) != null ) {
|
||||
if ( getAnnotationMirror( element, ORG_HIBERNATE_ANNOTATIONS_TYPE ) != null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BasicAttributeVisitor basicVisitor = new BasicAttributeVisitor( context );
|
||||
return returnedElement.asType().accept( basicVisitor, returnedElement );
|
||||
return returnedElement.asType().accept( new BasicAttributeVisitor( context ), returnedElement );
|
||||
}
|
||||
|
||||
private @Nullable AnnotationMetaAttribute createAnnotationMetaAttributeForMap(DeclaredType declaredType, Element element, String collection, @Nullable String targetEntity) {
|
||||
final AnnotationMirror annotationMirror = TypeUtils.getAnnotationMirror( element, Constants.MAP_KEY_CLASS );
|
||||
String keyType;
|
||||
if ( annotationMirror != null ) {
|
||||
TypeMirror typeMirror = (TypeMirror) NullnessUtil.castNonNull(
|
||||
TypeUtils.getAnnotationValue( annotationMirror, TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME )
|
||||
);
|
||||
keyType = typeMirror.toString();
|
||||
}
|
||||
else {
|
||||
keyType = TypeUtils.getKeyType( declaredType, context );
|
||||
}
|
||||
return new AnnotationMetaMap(
|
||||
entity,
|
||||
element,
|
||||
collection,
|
||||
keyType,
|
||||
getElementType( declaredType, targetEntity )
|
||||
);
|
||||
private String getMapKeyType(DeclaredType declaredType, Element element) {
|
||||
final AnnotationMirror annotationMirror = getAnnotationMirror(element, Constants.MAP_KEY_CLASS );
|
||||
return annotationMirror == null
|
||||
? getKeyType( declaredType, context )
|
||||
: castNonNull( getAnnotationValue( annotationMirror, DEFAULT_ANNOTATION_PARAMETER_NAME ) ).toString();
|
||||
}
|
||||
|
||||
private String getElementType(DeclaredType declaredType, @Nullable String targetEntity) {
|
||||
if ( targetEntity != null ) {
|
||||
return targetEntity;
|
||||
}
|
||||
final List<? extends TypeMirror> mirrors = declaredType.getTypeArguments();
|
||||
if ( mirrors.size() == 1 ) {
|
||||
final TypeMirror type = mirrors.get( 0 );
|
||||
return TypeUtils.extractClosestRealTypeAsString( type, context );
|
||||
}
|
||||
else if ( mirrors.size() == 2 ) {
|
||||
return TypeUtils.extractClosestRealTypeAsString( mirrors.get( 1 ), context );
|
||||
}
|
||||
else {
|
||||
//for 0 or many
|
||||
//0 is expected, many is not
|
||||
if ( mirrors.size() > 2 ) {
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.WARNING, "Unable to find the closest solid type" + declaredType
|
||||
);
|
||||
final List<? extends TypeMirror> mirrors = declaredType.getTypeArguments();
|
||||
switch ( mirrors.size() ) {
|
||||
case 0:
|
||||
return "?";
|
||||
case 1:
|
||||
return extractClosestRealTypeAsString( mirrors.get( 0 ), context );
|
||||
case 2:
|
||||
return extractClosestRealTypeAsString( mirrors.get( 1 ), context );
|
||||
default:
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.WARNING,
|
||||
"Unable to find the closest solid type" + declaredType
|
||||
);
|
||||
return "?";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,37 +243,35 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<@Nullable
|
|||
* @return target entity class name as string or {@code null} if no targetEntity is here or if equals to void
|
||||
*/
|
||||
private @Nullable String getTargetEntity(List<? extends AnnotationMirror> annotations) {
|
||||
String fullyQualifiedTargetEntityName = null;
|
||||
for ( AnnotationMirror mirror : annotations ) {
|
||||
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ELEMENT_COLLECTION ) ) {
|
||||
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetClass" );
|
||||
if ( isAnnotationMirrorOfType( mirror, Constants.ELEMENT_COLLECTION ) ) {
|
||||
return getFullyQualifiedClassNameOfTargetEntity( mirror, "targetClass" );
|
||||
}
|
||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ONE_TO_MANY )
|
||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, Constants.MANY_TO_MANY )
|
||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, Constants.MANY_TO_ONE )
|
||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ONE_TO_ONE ) ) {
|
||||
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "targetEntity" );
|
||||
else if ( isAnnotationMirrorOfType( mirror, Constants.ONE_TO_MANY )
|
||||
|| isAnnotationMirrorOfType( mirror, Constants.MANY_TO_MANY )
|
||||
|| isAnnotationMirrorOfType( mirror, Constants.MANY_TO_ONE )
|
||||
|| isAnnotationMirrorOfType( mirror, Constants.ONE_TO_ONE ) ) {
|
||||
return getFullyQualifiedClassNameOfTargetEntity( mirror, "targetEntity" );
|
||||
}
|
||||
else if ( TypeUtils.isAnnotationMirrorOfType( mirror, ORG_HIBERNATE_ANNOTATIONS_TARGET ) ) {
|
||||
fullyQualifiedTargetEntityName = getFullyQualifiedClassNameOfTargetEntity( mirror, "value" );
|
||||
else if ( isAnnotationMirrorOfType( mirror, ORG_HIBERNATE_ANNOTATIONS_TARGET ) ) {
|
||||
return getFullyQualifiedClassNameOfTargetEntity( mirror, "value" );
|
||||
}
|
||||
}
|
||||
return fullyQualifiedTargetEntityName;
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable String getFullyQualifiedClassNameOfTargetEntity(AnnotationMirror mirror, String parameterName) {
|
||||
assert mirror != null;
|
||||
assert parameterName != null;
|
||||
|
||||
String targetEntityName = null;
|
||||
Object parameterValue = TypeUtils.getAnnotationValue( mirror, parameterName );
|
||||
final Object parameterValue = getAnnotationValue( mirror, parameterName );
|
||||
if ( parameterValue != null ) {
|
||||
TypeMirror parameterType = (TypeMirror) parameterValue;
|
||||
if ( !parameterType.getKind().equals( TypeKind.VOID ) ) {
|
||||
targetEntityName = parameterType.toString();
|
||||
final TypeMirror parameterType = (TypeMirror) parameterValue;
|
||||
if ( parameterType.getKind() != TypeKind.VOID ) {
|
||||
return parameterType.toString();
|
||||
}
|
||||
}
|
||||
return targetEntityName;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,51 +279,49 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<@Nullable
|
|||
* Checks whether the visited type is a basic attribute according to the JPA 2 spec
|
||||
* ( section 2.8 Mapping Defaults for Non-Relationship Fields or Properties)
|
||||
*/
|
||||
class BasicAttributeVisitor extends SimpleTypeVisitor6<Boolean, Element> {
|
||||
class BasicAttributeVisitor extends SimpleTypeVisitor8<Boolean, Element> {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public BasicAttributeVisitor(Context context) {
|
||||
super( Boolean.FALSE );
|
||||
super( false );
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitPrimitive(PrimitiveType t, Element element) {
|
||||
return Boolean.TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitArray(ArrayType t, Element element) {
|
||||
TypeMirror componentMirror = t.getComponentType();
|
||||
TypeElement componentElement = (TypeElement) context.getTypeUtils().asElement( componentMirror );
|
||||
|
||||
final TypeElement componentElement = (TypeElement)
|
||||
context.getTypeUtils().asElement( t.getComponentType() );
|
||||
return Constants.BASIC_ARRAY_TYPES.contains( componentElement.getQualifiedName().toString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitDeclared(DeclaredType declaredType, Element element) {
|
||||
if ( ElementKind.ENUM.equals( element.getKind() ) ) {
|
||||
return Boolean.TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ( element.getKind().isClass() && !ElementKind.ENUM.equals( element.getKind() ) ) ||
|
||||
ElementKind.INTERFACE.equals( element.getKind() ) ) {
|
||||
TypeElement typeElement = ( (TypeElement) element );
|
||||
String typeName = typeElement.getQualifiedName().toString();
|
||||
if ( element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE ) {
|
||||
final TypeElement typeElement = (TypeElement) element;
|
||||
final String typeName = typeElement.getQualifiedName().toString();
|
||||
if ( Constants.BASIC_TYPES.contains( typeName ) ) {
|
||||
return Boolean.TRUE;
|
||||
return true;
|
||||
}
|
||||
if ( TypeUtils.containsAnnotation( element, Constants.EMBEDDABLE ) ) {
|
||||
return Boolean.TRUE;
|
||||
if ( containsAnnotation( element, Constants.EMBEDDABLE ) ) {
|
||||
return true;
|
||||
}
|
||||
for ( TypeMirror mirror : typeElement.getInterfaces() ) {
|
||||
TypeElement interfaceElement = (TypeElement) context.getTypeUtils().asElement( mirror );
|
||||
if ( "java.io.Serializable".equals( interfaceElement.getQualifiedName().toString() ) ) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
final TypeMirror serializableType =
|
||||
context.getElementUtils().getTypeElement("java.io.Serializable").asType();
|
||||
if ( context.getTypeUtils().isSubtype( typeElement.asType(), serializableType) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public class QueryMethod implements MetaAttribute {
|
|||
@Override
|
||||
public String getAttributeDeclarationString() {
|
||||
List<String> paramTypes = this.paramTypes.stream()
|
||||
.map(ptype->isOrderParam(ptype) && ptype.endsWith("[]") ? ptype.replace("[]", "...") : ptype)
|
||||
.map(ptype->isOrderParam(ptype) && ptype.endsWith("[]") ? ptype.substring(0, ptype.length()-2) + "..." : ptype)
|
||||
.collect(toList());
|
||||
StringBuilder declaration = new StringBuilder();
|
||||
declaration
|
||||
|
|
|
@ -25,6 +25,7 @@ public final class Constants {
|
|||
public static final String ONE_TO_MANY = "jakarta.persistence.OneToMany";
|
||||
public static final String MANY_TO_ONE = "jakarta.persistence.ManyToOne";
|
||||
public static final String MANY_TO_MANY = "jakarta.persistence.ManyToMany";
|
||||
public static final String MANY_TO_ANY = "org.hibernate.annotations.ManyToAny";
|
||||
public static final String MAP_KEY_CLASS = "jakarta.persistence.MapKeyClass";
|
||||
public static final String ELEMENT_COLLECTION = "jakarta.persistence.ElementCollection";
|
||||
public static final String ACCESS = "jakarta.persistence.Access";
|
||||
|
|
|
@ -50,7 +50,8 @@ public final class StringUtil {
|
|||
return true;
|
||||
}
|
||||
|
||||
if ( isValidPropertyName( methodName, PROPERTY_PREFIX_IS ) || isValidPropertyName( methodName, PROPERTY_PREFIX_HAS ) ) {
|
||||
if ( isValidPropertyName( methodName, PROPERTY_PREFIX_IS )
|
||||
|| isValidPropertyName( methodName, PROPERTY_PREFIX_HAS ) ) {
|
||||
return isBooleanGetter( returnTypeAsString );
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.jpamodelgen.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -24,9 +22,9 @@ 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.type.WildcardType;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||
import javax.lang.model.util.SimpleTypeVisitor8;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import org.hibernate.jpamodelgen.Context;
|
||||
|
@ -34,6 +32,9 @@ import org.hibernate.jpamodelgen.MetaModelGenerationException;
|
|||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull;
|
||||
import static org.hibernate.jpamodelgen.util.StringUtil.isProperty;
|
||||
|
||||
/**
|
||||
* Utility class.
|
||||
*
|
||||
|
@ -44,8 +45,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||
public final class TypeUtils {
|
||||
|
||||
public static final String DEFAULT_ANNOTATION_PARAMETER_NAME = "value";
|
||||
private static final Map<TypeKind, String> PRIMITIVE_WRAPPERS = new HashMap<TypeKind, String>();
|
||||
private static final Map<TypeKind, String> PRIMITIVES = new HashMap<TypeKind, String>();
|
||||
private static final Map<TypeKind, String> PRIMITIVE_WRAPPERS = new HashMap<>();
|
||||
private static final Map<TypeKind, String> PRIMITIVES = new HashMap<>();
|
||||
|
||||
static {
|
||||
PRIMITIVE_WRAPPERS.put( TypeKind.CHAR, "Character" );
|
||||
|
@ -74,35 +75,34 @@ public final class TypeUtils {
|
|||
}
|
||||
|
||||
public static String toTypeString(TypeMirror type) {
|
||||
if ( type.getKind().isPrimitive() ) {
|
||||
return NullnessUtil.castNonNull( PRIMITIVE_WRAPPERS.get( type.getKind() ) );
|
||||
}
|
||||
return TypeRenderingVisitor.toString( type );
|
||||
return type.getKind().isPrimitive()
|
||||
? castNonNull( PRIMITIVE_WRAPPERS.get( type.getKind() ) )
|
||||
: TypeRenderingVisitor.toString( type );
|
||||
}
|
||||
|
||||
public static String toArrayTypeString(ArrayType type, Context context) {
|
||||
TypeMirror componentType = type.getComponentType();
|
||||
final TypeMirror componentType = type.getComponentType();
|
||||
if ( componentType.getKind().isPrimitive() ) {
|
||||
return PRIMITIVES.get( componentType.getKind() ) + "[]";
|
||||
}
|
||||
|
||||
// When an ArrayType is annotated with an annotation which uses TYPE_USE targets,
|
||||
// we cannot simply take the TypeMirror returned by #getComponentType because it
|
||||
// itself is an AnnotatedType.
|
||||
//
|
||||
// The simplest approach here to get the TypeMirror for both ArrayType use cases
|
||||
// is to use the visitor to retrieve the underlying TypeMirror.
|
||||
TypeMirror component = componentType.accept(
|
||||
new SimpleTypeVisitor6<TypeMirror, Void>() {
|
||||
@Override
|
||||
protected TypeMirror defaultAction(TypeMirror e, Void aVoid) {
|
||||
return e;
|
||||
}
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
return extractClosestRealTypeAsString( component, context ) + "[]";
|
||||
else {
|
||||
// When an ArrayType is annotated with an annotation which uses TYPE_USE targets,
|
||||
// we cannot simply take the TypeMirror returned by #getComponentType because it
|
||||
// itself is an AnnotatedType.
|
||||
//
|
||||
// The simplest approach here to get the TypeMirror for both ArrayType use cases
|
||||
// is to use the visitor to retrieve the underlying TypeMirror.
|
||||
final TypeMirror component = componentType.accept(
|
||||
new SimpleTypeVisitor8<TypeMirror, Void>() {
|
||||
@Override
|
||||
protected TypeMirror defaultAction(TypeMirror e, Void aVoid) {
|
||||
return e;
|
||||
}
|
||||
},
|
||||
null
|
||||
);
|
||||
return extractClosestRealTypeAsString( component, context ) + "[]";
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable TypeElement getSuperclassTypeElement(TypeElement element) {
|
||||
|
@ -119,31 +119,53 @@ public final class TypeUtils {
|
|||
}
|
||||
|
||||
public static String extractClosestRealTypeAsString(TypeMirror type, Context context) {
|
||||
if ( type instanceof TypeVariable ) {
|
||||
final TypeMirror compositeUpperBound = ( (TypeVariable) type ).getUpperBound();
|
||||
return extractClosestRealTypeAsString( compositeUpperBound, context );
|
||||
final TypeMirror mirror = extractClosestRealType( type, context );
|
||||
return mirror == null ? "?" : mirror.toString();
|
||||
}
|
||||
|
||||
private static @Nullable TypeMirror lowerBound(TypeMirror bound) {
|
||||
return bound.getKind() == TypeKind.NULL ? null : bound;
|
||||
}
|
||||
|
||||
private static @Nullable TypeMirror upperBound(TypeMirror bound) {
|
||||
return bound.getKind() == TypeKind.DECLARED && bound.toString().equals("java.lang.Object") ? null : bound;
|
||||
}
|
||||
|
||||
@SuppressWarnings("nullness")
|
||||
public static TypeMirror extractClosestRealType(TypeMirror type, Context context) {
|
||||
if ( type == null ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
final TypeMirror erasureType = context.getTypeUtils().erasure( type );
|
||||
if ( TypeKind.ARRAY.equals( erasureType.getKind() ) ) {
|
||||
// keep old behavior here for arrays since #asElement returns null for them.
|
||||
return erasureType.toString();
|
||||
}
|
||||
else {
|
||||
return ( (TypeElement) context.getTypeUtils().asElement( erasureType ) ).getQualifiedName().toString();
|
||||
}
|
||||
switch ( type.getKind() ) {
|
||||
case TYPEVAR:
|
||||
final TypeVariable typeVariable = (TypeVariable) type;
|
||||
return context.getTypeUtils().getWildcardType(
|
||||
upperBound( extractClosestRealType( typeVariable.getUpperBound(), context ) ),
|
||||
lowerBound( extractClosestRealType( typeVariable.getLowerBound(), context ) )
|
||||
);
|
||||
case WILDCARD:
|
||||
final WildcardType wildcardType = (WildcardType) type;
|
||||
return context.getTypeUtils().getWildcardType(
|
||||
extractClosestRealType( wildcardType.getExtendsBound(), context ),
|
||||
extractClosestRealType( wildcardType.getSuperBound(), context )
|
||||
);
|
||||
case DECLARED:
|
||||
final DeclaredType declaredType = (DeclaredType) type;
|
||||
final TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
return context.getTypeUtils().getDeclaredType( typeElement,
|
||||
declaredType.getTypeArguments().stream()
|
||||
.map( arg -> extractClosestRealType( arg, context ) )
|
||||
.toArray( TypeMirror[]::new ) );
|
||||
default:
|
||||
return context.getTypeUtils().erasure( type );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean containsAnnotation(Element element, String... annotations) {
|
||||
assert element != null;
|
||||
assert annotations != null;
|
||||
|
||||
Set<String> annotationClassNames = new HashSet<>();
|
||||
Collections.addAll( annotationClassNames, annotations );
|
||||
|
||||
List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
|
||||
for ( AnnotationMirror mirror : annotationMirrors ) {
|
||||
final Set<String> annotationClassNames = Set.of(annotations);
|
||||
for ( AnnotationMirror mirror : element.getAnnotationMirrors() ) {
|
||||
if ( annotationClassNames.contains( mirror.getAnnotationType().toString() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
@ -164,9 +186,7 @@ public final class TypeUtils {
|
|||
public static boolean isAnnotationMirrorOfType(AnnotationMirror annotationMirror, String fqcn) {
|
||||
assert annotationMirror != null;
|
||||
assert fqcn != null;
|
||||
String annotationClassName = annotationMirror.getAnnotationType().toString();
|
||||
|
||||
return annotationClassName.equals( fqcn );
|
||||
return annotationMirror.getAnnotationType().toString().equals( fqcn );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,121 +201,114 @@ public final class TypeUtils {
|
|||
public static @Nullable AnnotationMirror getAnnotationMirror(Element element, String fqcn) {
|
||||
assert element != null;
|
||||
assert fqcn != null;
|
||||
|
||||
AnnotationMirror mirror = null;
|
||||
for ( AnnotationMirror am : element.getAnnotationMirrors() ) {
|
||||
if ( isAnnotationMirrorOfType( am, fqcn ) ) {
|
||||
mirror = am;
|
||||
break;
|
||||
for ( AnnotationMirror mirror : element.getAnnotationMirrors() ) {
|
||||
if ( isAnnotationMirrorOfType( mirror, fqcn ) ) {
|
||||
return mirror;
|
||||
}
|
||||
}
|
||||
return mirror;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) {
|
||||
assert annotationMirror != null;
|
||||
assert parameterValue != null;
|
||||
|
||||
Object returnValue = null;
|
||||
for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : annotationMirror.getElementValues()
|
||||
.entrySet() ) {
|
||||
for ( Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry
|
||||
: annotationMirror.getElementValues().entrySet() ) {
|
||||
if ( parameterValue.equals( entry.getKey().getSimpleName().toString() ) ) {
|
||||
returnValue = entry.getValue().getValue();
|
||||
break;
|
||||
return entry.getValue().getValue();
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void determineAccessTypeForHierarchy(TypeElement searchedElement, Context context) {
|
||||
String fqcn = searchedElement.getQualifiedName().toString();
|
||||
final String fqcn = searchedElement.getQualifiedName().toString();
|
||||
context.logMessage( Diagnostic.Kind.OTHER, "Determining access type for " + fqcn );
|
||||
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn );
|
||||
|
||||
final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn );
|
||||
if ( accessTypeInfo != null && accessTypeInfo.isAccessTypeResolved() ) {
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.OTHER,
|
||||
"AccessType for " + searchedElement.toString() + " found in cache: " + accessTypeInfo
|
||||
"AccessType for " + searchedElement + " 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 );
|
||||
setDefaultAccessTypeForMappedSuperclassesInHierarchy( searchedElement, defaultAccessType, context );
|
||||
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 );
|
||||
updateEmbeddableAccessType( searchedElement, context, defaultAccessType );
|
||||
}
|
||||
|
||||
public static TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, @Nullable String explicitTargetEntityName, Context context) {
|
||||
TypeMirror collectionElementType;
|
||||
if ( explicitTargetEntityName != null ) {
|
||||
Elements elements = context.getElementUtils();
|
||||
TypeElement element = elements.getTypeElement( explicitTargetEntityName );
|
||||
collectionElementType = element.asType();
|
||||
}
|
||||
else {
|
||||
List<? extends TypeMirror> typeArguments = t.getTypeArguments();
|
||||
// check for explicit access type
|
||||
final AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( searchedElement) ;
|
||||
if ( forcedAccessType != null ) {
|
||||
context.logMessage(
|
||||
Diagnostic.Kind.OTHER,
|
||||
"Explicit access type on " + searchedElement + ":" + forcedAccessType
|
||||
);
|
||||
final AccessTypeInformation newAccessTypeInfo =
|
||||
new AccessTypeInformation( fqcn, forcedAccessType, null );
|
||||
context.addAccessTypeInformation( fqcn, newAccessTypeInfo );
|
||||
updateEmbeddableAccessType( searchedElement, context, forcedAccessType );
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
final AccessType defaultAccessType = getAccessTypeInCaseElementIsRoot( searchedElement, context );
|
||||
if ( defaultAccessType != null ) {
|
||||
final AccessTypeInformation newAccessTypeInfo =
|
||||
new AccessTypeInformation(fqcn, null, defaultAccessType);
|
||||
context.addAccessTypeInformation( fqcn, newAccessTypeInfo );
|
||||
updateEmbeddableAccessType( searchedElement, context, defaultAccessType );
|
||||
setDefaultAccessTypeForMappedSuperclassesInHierarchy( searchedElement, defaultAccessType, context );
|
||||
}
|
||||
else {
|
||||
// if we end up here we need to recursively look for superclasses
|
||||
AccessType newDefaultAccessType = getDefaultAccessForHierarchy( searchedElement, context );
|
||||
if ( newDefaultAccessType == null ) {
|
||||
//TODO: this default is arbitrary and very questionable!
|
||||
newDefaultAccessType = AccessType.PROPERTY;
|
||||
}
|
||||
final AccessTypeInformation newAccessTypeInfo =
|
||||
new AccessTypeInformation( fqcn, null, newDefaultAccessType );
|
||||
context.addAccessTypeInformation( fqcn, newAccessTypeInfo );
|
||||
updateEmbeddableAccessType( searchedElement, context, newDefaultAccessType );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeMirror getCollectionElementType(
|
||||
DeclaredType t, String fqNameOfReturnedType, @Nullable String explicitTargetEntityName, Context context) {
|
||||
if ( explicitTargetEntityName != null ) {
|
||||
return context.getElementUtils().getTypeElement( explicitTargetEntityName ).asType();
|
||||
}
|
||||
else {
|
||||
final List<? extends TypeMirror> 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 );
|
||||
return t.getTypeArguments().get( 1 );
|
||||
}
|
||||
else {
|
||||
collectionElementType = t.getTypeArguments().get( 0 );
|
||||
return t.getTypeArguments().get( 0 );
|
||||
}
|
||||
}
|
||||
return collectionElementType;
|
||||
}
|
||||
|
||||
private static void updateEmbeddableAccessType(TypeElement element, Context context, AccessType defaultAccessType) {
|
||||
List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() );
|
||||
for ( Element field : fieldsOfClass ) {
|
||||
for ( Element field : ElementFilter.fieldsIn( element.getEnclosedElements() ) ) {
|
||||
updateEmbeddableAccessTypeForMember( context, defaultAccessType, field );
|
||||
}
|
||||
|
||||
List<? extends Element> methodOfClass = ElementFilter.methodsIn( element.getEnclosedElements() );
|
||||
for ( Element method : methodOfClass ) {
|
||||
for ( Element method : ElementFilter.methodsIn( element.getEnclosedElements() ) ) {
|
||||
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 );
|
||||
final String embeddedClassName = member.asType().accept( new EmbeddedAttributeVisitor( context ), member );
|
||||
if ( embeddedClassName != null ) {
|
||||
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( embeddedClassName );
|
||||
final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( embeddedClassName );
|
||||
if ( accessTypeInfo == null ) {
|
||||
accessTypeInfo = new AccessTypeInformation( embeddedClassName, null, defaultAccessType );
|
||||
context.addAccessTypeInformation( embeddedClassName, accessTypeInfo );
|
||||
final AccessTypeInformation newAccessTypeInfo =
|
||||
new AccessTypeInformation( embeddedClassName, null, defaultAccessType );
|
||||
context.addAccessTypeInformation( embeddedClassName, newAccessTypeInfo );
|
||||
}
|
||||
else {
|
||||
accessTypeInfo.setDefaultAccessType( defaultAccessType );
|
||||
|
@ -307,18 +320,19 @@ public final class TypeUtils {
|
|||
AccessType defaultAccessType = null;
|
||||
TypeElement superClass = element;
|
||||
do {
|
||||
superClass = TypeUtils.getSuperclassTypeElement( superClass );
|
||||
superClass = getSuperclassTypeElement( superClass );
|
||||
if ( superClass != null ) {
|
||||
String fqcn = superClass.getQualifiedName().toString();
|
||||
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn );
|
||||
final String fqcn = superClass.getQualifiedName().toString();
|
||||
final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( fqcn );
|
||||
if ( accessTypeInfo != null && accessTypeInfo.getDefaultAccessType() != null ) {
|
||||
return accessTypeInfo.getDefaultAccessType();
|
||||
}
|
||||
if ( TypeUtils.containsAnnotation( superClass, Constants.ENTITY, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
if ( containsAnnotation( superClass, Constants.ENTITY, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
defaultAccessType = getAccessTypeInCaseElementIsRoot( superClass, context );
|
||||
if ( defaultAccessType != null ) {
|
||||
accessTypeInfo = new AccessTypeInformation( fqcn, null, defaultAccessType );
|
||||
context.addAccessTypeInformation( fqcn, accessTypeInfo );
|
||||
final AccessTypeInformation newAccessTypeInfo
|
||||
= new AccessTypeInformation( fqcn, null, defaultAccessType );
|
||||
context.addAccessTypeInformation( fqcn, newAccessTypeInfo );
|
||||
|
||||
// we found an id within the class hierarchy and determined a default access type
|
||||
// there cannot be any super entity classes (otherwise it would be a configuration error)
|
||||
|
@ -344,18 +358,15 @@ public final class TypeUtils {
|
|||
private static void setDefaultAccessTypeForMappedSuperclassesInHierarchy(TypeElement element, AccessType defaultAccessType, Context context) {
|
||||
TypeElement superClass = element;
|
||||
do {
|
||||
superClass = TypeUtils.getSuperclassTypeElement( superClass );
|
||||
superClass = getSuperclassTypeElement( superClass );
|
||||
if ( superClass != null ) {
|
||||
String fqcn = superClass.getQualifiedName().toString();
|
||||
if ( TypeUtils.containsAnnotation( superClass, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
AccessTypeInformation accessTypeInfo;
|
||||
AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( superClass );
|
||||
if ( forcedAccessType != null ) {
|
||||
accessTypeInfo = new AccessTypeInformation( fqcn, null, forcedAccessType );
|
||||
}
|
||||
else {
|
||||
accessTypeInfo = new AccessTypeInformation( fqcn, null, defaultAccessType );
|
||||
}
|
||||
final String fqcn = superClass.getQualifiedName().toString();
|
||||
if ( containsAnnotation( superClass, Constants.MAPPED_SUPERCLASS ) ) {
|
||||
final AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( superClass );
|
||||
final AccessTypeInformation accessTypeInfo =
|
||||
forcedAccessType != null
|
||||
? new AccessTypeInformation( fqcn, null, forcedAccessType )
|
||||
: new AccessTypeInformation( fqcn, null, defaultAccessType );
|
||||
context.addAccessTypeInformation( fqcn, accessTypeInfo );
|
||||
}
|
||||
}
|
||||
|
@ -374,13 +385,10 @@ public final class TypeUtils {
|
|||
* {@code null} is returned.
|
||||
*/
|
||||
private static @Nullable AccessType getAccessTypeInCaseElementIsRoot(TypeElement searchedElement, Context context) {
|
||||
List<? extends Element> myMembers = searchedElement.getEnclosedElements();
|
||||
for ( Element subElement : myMembers ) {
|
||||
List<? extends AnnotationMirror> entityAnnotations =
|
||||
context.getElementUtils().getAllAnnotationMirrors( subElement );
|
||||
for ( Object entityAnnotation : entityAnnotations ) {
|
||||
AnnotationMirror annotationMirror = (AnnotationMirror) entityAnnotation;
|
||||
if ( isIdAnnotation( annotationMirror ) ) {
|
||||
for ( Element subElement : searchedElement.getEnclosedElements() ) {
|
||||
for ( AnnotationMirror entityAnnotation :
|
||||
context.getElementUtils().getAllAnnotationMirrors( subElement ) ) {
|
||||
if ( isIdAnnotation( entityAnnotation ) ) {
|
||||
return getAccessTypeOfIdAnnotation( subElement );
|
||||
}
|
||||
}
|
||||
|
@ -389,57 +397,54 @@ public final class TypeUtils {
|
|||
}
|
||||
|
||||
private static @Nullable 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 kind == ElementKind.FIELD ? AccessType.FIELD : AccessType.PROPERTY;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return accessType;
|
||||
}
|
||||
|
||||
private static boolean isIdAnnotation(AnnotationMirror annotationMirror) {
|
||||
return TypeUtils.isAnnotationMirrorOfType( annotationMirror, Constants.ID )
|
||||
|| TypeUtils.isAnnotationMirrorOfType( annotationMirror, Constants.EMBEDDED_ID );
|
||||
return isAnnotationMirrorOfType( annotationMirror, Constants.ID )
|
||||
|| isAnnotationMirrorOfType( annotationMirror, Constants.EMBEDDED_ID );
|
||||
}
|
||||
|
||||
public static @Nullable AccessType determineAnnotationSpecifiedAccessType(Element element) {
|
||||
final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Constants.ACCESS );
|
||||
AccessType forcedAccessType = null;
|
||||
if ( accessAnnotationMirror != null ) {
|
||||
Element accessElement = (Element) NullnessUtil.castNonNull(
|
||||
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;
|
||||
final Element accessElement = (Element)
|
||||
castNonNull( getAnnotationValue( accessAnnotationMirror, DEFAULT_ANNOTATION_PARAMETER_NAME ) );
|
||||
if ( accessElement.getKind() == ElementKind.ENUM_CONSTANT ) {
|
||||
if ( accessElement.getSimpleName().contentEquals( AccessType.PROPERTY.toString() ) ) {
|
||||
return AccessType.PROPERTY;
|
||||
}
|
||||
else if ( accessElement.getSimpleName().toString().equals( AccessType.FIELD.toString() ) ) {
|
||||
forcedAccessType = AccessType.FIELD;
|
||||
else if ( accessElement.getSimpleName().contentEquals( AccessType.FIELD.toString() ) ) {
|
||||
return AccessType.FIELD;
|
||||
}
|
||||
}
|
||||
}
|
||||
return forcedAccessType;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ElementKind getElementKindForAccessType(AccessType accessType) {
|
||||
if ( AccessType.FIELD.equals( accessType ) ) {
|
||||
return ElementKind.FIELD;
|
||||
return accessType == AccessType.FIELD ? ElementKind.FIELD : ElementKind.METHOD;
|
||||
}
|
||||
|
||||
public static String getKeyType(DeclaredType type, Context context) {
|
||||
final List<? extends TypeMirror> typeArguments = type.getTypeArguments();
|
||||
if ( typeArguments.isEmpty() ) {
|
||||
context.logMessage( Diagnostic.Kind.ERROR, "Unable to determine type argument for " + type );
|
||||
return "java.lang.Object";
|
||||
}
|
||||
else {
|
||||
return ElementKind.METHOD;
|
||||
return extractClosestRealTypeAsString( typeArguments.get( 0 ), context );
|
||||
}
|
||||
}
|
||||
|
||||
public static String getKeyType(DeclaredType t, Context context) {
|
||||
List<? extends TypeMirror> typeArguments = t.getTypeArguments();
|
||||
if ( typeArguments.size() == 0 ) {
|
||||
context.logMessage( Diagnostic.Kind.ERROR, "Unable to determine type argument for " + t );
|
||||
}
|
||||
return extractClosestRealTypeAsString( typeArguments.get( 0 ), context );
|
||||
}
|
||||
|
||||
static class EmbeddedAttributeVisitor extends SimpleTypeVisitor6<@Nullable String, Element> {
|
||||
private Context context;
|
||||
static class EmbeddedAttributeVisitor extends SimpleTypeVisitor8<@Nullable String, Element> {
|
||||
private final Context context;
|
||||
|
||||
EmbeddedAttributeVisitor(Context context) {
|
||||
this.context = context;
|
||||
|
@ -447,27 +452,24 @@ public final class TypeUtils {
|
|||
|
||||
@Override
|
||||
public @Nullable String visitDeclared(DeclaredType declaredType, Element element) {
|
||||
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
||||
String fqNameOfReturnType = null;
|
||||
if ( containsAnnotation( returnedElement, Constants.EMBEDDABLE ) ) {
|
||||
fqNameOfReturnType = returnedElement.getQualifiedName().toString();
|
||||
}
|
||||
return fqNameOfReturnType;
|
||||
final TypeElement returnedElement = (TypeElement)
|
||||
context.getTypeUtils().asElement( declaredType );
|
||||
return containsAnnotation( returnedElement, Constants.EMBEDDABLE )
|
||||
? returnedElement.getQualifiedName().toString()
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String visitExecutable(ExecutableType t, Element p) {
|
||||
if ( !p.getKind().equals( ElementKind.METHOD ) ) {
|
||||
if ( p.getKind().equals( ElementKind.METHOD ) ) {
|
||||
String string = p.getSimpleName().toString();
|
||||
return isProperty( string, toTypeString( t.getReturnType() ) )
|
||||
? t.getReturnType().accept(this, p)
|
||||
: null;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
String string = p.getSimpleName().toString();
|
||||
if ( !StringUtil.isProperty( string, TypeUtils.toTypeString( t.getReturnType() ) ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeMirror returnType = t.getReturnType();
|
||||
return returnType.accept( this, p );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -525,12 +525,11 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
TypeMirror type = member.asType();
|
||||
final TypeMirror type = member.asType();
|
||||
if (type.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) type;
|
||||
TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
//TODO: something better here!
|
||||
return typeElement.getSuperclass().toString().startsWith("java.lang.Enum");
|
||||
final DeclaredType declaredType = (DeclaredType) type;
|
||||
final TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
return typeElement.getKind() == ElementKind.ENUM;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
@ -547,7 +546,7 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
TypeMirror type = member.asType();
|
||||
final TypeMirror type = member.asType();
|
||||
return type.getKind() == TypeKind.DECLARED
|
||||
&& hasAnnotation(type, "Embeddable");
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.antlr.v4.runtime.atn.PredictionMode;
|
|||
import org.antlr.v4.runtime.misc.ParseCancellationException;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.grammars.hql.HqlLexer;
|
||||
import org.hibernate.grammars.hql.HqlParser;
|
||||
import org.hibernate.query.hql.internal.HqlParseTreeBuilder;
|
||||
|
@ -46,68 +47,32 @@ public class Validation {
|
|||
}
|
||||
|
||||
public static void validate(
|
||||
String hql, boolean checkParams,
|
||||
String hql,
|
||||
boolean checkParams, boolean checkTyping,
|
||||
Set<Integer> setParameterLabels,
|
||||
Set<String> setParameterNames,
|
||||
Handler handler,
|
||||
MockSessionFactory factory) {
|
||||
validate(hql, checkParams, setParameterLabels, setParameterNames, handler, factory, 0);
|
||||
SessionFactoryImplementor factory) {
|
||||
validate( hql, checkParams, checkTyping, setParameterLabels, setParameterNames, handler, factory, 0 );
|
||||
}
|
||||
|
||||
public static void validate(
|
||||
String hql, boolean checkParams,
|
||||
String hql,
|
||||
boolean checkParams, boolean checkTyping,
|
||||
Set<Integer> setParameterLabels,
|
||||
Set<String> setParameterNames,
|
||||
Handler handler,
|
||||
MockSessionFactory factory,
|
||||
SessionFactoryImplementor factory,
|
||||
int errorOffset) {
|
||||
// handler = new Filter(handler, errorOffset);
|
||||
|
||||
try {
|
||||
|
||||
final HqlLexer hqlLexer = HqlParseTreeBuilder.INSTANCE.buildHqlLexer( hql );
|
||||
final HqlParser hqlParser = HqlParseTreeBuilder.INSTANCE.buildHqlParser( hql, hqlLexer );
|
||||
hqlLexer.addErrorListener( handler );
|
||||
hqlParser.getInterpreter().setPredictionMode( PredictionMode.SLL );
|
||||
hqlParser.removeErrorListeners();
|
||||
hqlParser.addErrorListener( handler );
|
||||
hqlParser.setErrorHandler( new BailErrorStrategy() );
|
||||
|
||||
HqlParser.StatementContext statementContext;
|
||||
try {
|
||||
statementContext = hqlParser.statement();
|
||||
final HqlParser.StatementContext statementContext = parseAndCheckSyntax( hql, handler );
|
||||
if ( checkTyping && handler.getErrorCount() == 0 ) {
|
||||
checkTyping( hql, handler, factory, errorOffset, statementContext );
|
||||
}
|
||||
catch ( ParseCancellationException e) {
|
||||
// reset the input token stream and parser state
|
||||
hqlLexer.reset();
|
||||
hqlParser.reset();
|
||||
|
||||
// fall back to LL(k)-based parsing
|
||||
hqlParser.getInterpreter().setPredictionMode( PredictionMode.LL );
|
||||
hqlParser.setErrorHandler( new DefaultErrorStrategy() );
|
||||
|
||||
statementContext = hqlParser.statement();
|
||||
|
||||
}
|
||||
if (handler.getErrorCount() == 0) {
|
||||
try {
|
||||
new SemanticQueryBuilder<>(Object[].class, () -> false, factory)
|
||||
.visitStatement( statementContext );
|
||||
}
|
||||
catch (JdbcTypeRecommendationException ignored) {
|
||||
// just squash these for now
|
||||
}
|
||||
catch (QueryException | PathElementException | TerminalPathException | EntityTypeException
|
||||
| PropertyNotFoundException se) { //TODO is this one really thrown by core? It should not be!
|
||||
String message = se.getMessage();
|
||||
if ( message != null ) {
|
||||
handler.error(-errorOffset+1, -errorOffset + hql.length(), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkParams) {
|
||||
checkParameterBinding(hql, setParameterLabels, setParameterNames, handler, errorOffset);
|
||||
if ( checkParams ) {
|
||||
checkParameterBinding( hql, setParameterLabels, setParameterNames, handler, errorOffset );
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -115,6 +80,53 @@ public class Validation {
|
|||
}
|
||||
}
|
||||
|
||||
private static void checkTyping(
|
||||
String hql,
|
||||
Handler handler,
|
||||
SessionFactoryImplementor factory,
|
||||
int errorOffset,
|
||||
HqlParser.StatementContext statementContext) {
|
||||
try {
|
||||
new SemanticQueryBuilder<>( Object[].class, () -> false, factory )
|
||||
.visitStatement( statementContext );
|
||||
}
|
||||
catch ( JdbcTypeRecommendationException ignored ) {
|
||||
// just squash these for now
|
||||
}
|
||||
catch ( QueryException | PathElementException | TerminalPathException | EntityTypeException
|
||||
| PropertyNotFoundException se ) { //TODO is this one really thrown by core? It should not be!
|
||||
String message = se.getMessage();
|
||||
if ( message != null ) {
|
||||
handler.error( -errorOffset +1, -errorOffset + hql.length(), message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static HqlParser.StatementContext parseAndCheckSyntax(String hql, Handler handler) {
|
||||
final HqlLexer hqlLexer = HqlParseTreeBuilder.INSTANCE.buildHqlLexer( hql );
|
||||
final HqlParser hqlParser = HqlParseTreeBuilder.INSTANCE.buildHqlParser( hql, hqlLexer );
|
||||
hqlLexer.addErrorListener( handler );
|
||||
hqlParser.getInterpreter().setPredictionMode( PredictionMode.SLL );
|
||||
hqlParser.removeErrorListeners();
|
||||
hqlParser.addErrorListener( handler );
|
||||
hqlParser.setErrorHandler( new BailErrorStrategy() );
|
||||
|
||||
try {
|
||||
return hqlParser.statement();
|
||||
}
|
||||
catch ( ParseCancellationException e) {
|
||||
// reset the input token stream and parser state
|
||||
hqlLexer.reset();
|
||||
hqlParser.reset();
|
||||
|
||||
// fall back to LL(k)-based parsing
|
||||
hqlParser.getInterpreter().setPredictionMode( PredictionMode.LL );
|
||||
hqlParser.setErrorHandler( new DefaultErrorStrategy() );
|
||||
|
||||
return hqlParser.statement();
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkParameterBinding(
|
||||
String hql,
|
||||
Set<Integer> setParameterLabels,
|
||||
|
@ -143,10 +155,10 @@ public class Validation {
|
|||
String text = next.getText();
|
||||
switch (tokenType) {
|
||||
case HqlLexer.COLON:
|
||||
if (!text.isEmpty()
|
||||
&& isJavaIdentifierStart(text.codePointAt(0))) {
|
||||
if ( !text.isEmpty()
|
||||
&& isJavaIdentifierStart( text.codePointAt(0) ) ) {
|
||||
names.add(text);
|
||||
if (setParameterNames.contains(text)) {
|
||||
if ( setParameterNames.contains(text) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +167,7 @@ public class Validation {
|
|||
}
|
||||
break;
|
||||
case HqlLexer.QUESTION_MARK:
|
||||
if (next.getType() == HqlLexer.INTEGER_LITERAL) {
|
||||
if ( next.getType() == HqlLexer.INTEGER_LITERAL ) {
|
||||
int label;
|
||||
try {
|
||||
label = parseInt(text);
|
||||
|
@ -164,7 +176,7 @@ public class Validation {
|
|||
continue;
|
||||
}
|
||||
labels.add(label);
|
||||
if (setParameterLabels.contains(label)) {
|
||||
if ( setParameterLabels.contains(label) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -186,34 +198,38 @@ public class Validation {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (unsetParams != null) {
|
||||
handler.warn(start-errorOffset+1, end-errorOffset, parameters + unsetParams + notSet);
|
||||
if ( unsetParams != null ) {
|
||||
handler.warn( start-errorOffset+1, end-errorOffset, parameters + unsetParams + notSet );
|
||||
}
|
||||
|
||||
setParameterNames.removeAll(names);
|
||||
setParameterLabels.removeAll(labels);
|
||||
|
||||
int count = setParameterNames.size() + setParameterLabels.size();
|
||||
if (count > 0) {
|
||||
String missingParams =
|
||||
concat(setParameterNames.stream().map(name -> ":" + name),
|
||||
setParameterLabels.stream().map(label -> "?" + label))
|
||||
.reduce((x, y) -> x + ", " + y)
|
||||
.orElse(null);
|
||||
String params =
|
||||
count == 1 ?
|
||||
"Parameter " :
|
||||
"Parameters ";
|
||||
String notOccur =
|
||||
count == 1 ?
|
||||
" does not occur in the query" :
|
||||
" do not occur in the query";
|
||||
handler.warn(0, 0, params + missingParams + notOccur);
|
||||
}
|
||||
reportMissingParams( setParameterLabels, setParameterNames, handler );
|
||||
}
|
||||
finally {
|
||||
setParameterNames.clear();
|
||||
setParameterLabels.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportMissingParams(Set<Integer> setParameterLabels, Set<String> setParameterNames, Handler handler) {
|
||||
final int count = setParameterNames.size() + setParameterLabels.size();
|
||||
if (count > 0) {
|
||||
final String missingParams =
|
||||
concat( setParameterNames.stream().map(name -> ":" + name),
|
||||
setParameterLabels.stream().map(label -> "?" + label) )
|
||||
.reduce((x, y) -> x + ", " + y)
|
||||
.orElse(null);
|
||||
final String params =
|
||||
count == 1 ?
|
||||
"Parameter " :
|
||||
"Parameters ";
|
||||
final String notOccur =
|
||||
count == 1 ?
|
||||
" does not occur in the query" :
|
||||
" do not occur in the query";
|
||||
handler.warn(0, 0, params + missingParams + notOccur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,11 @@ package org.hibernate.jpamodelgen.test.elementcollection;
|
|||
|
||||
import org.hibernate.jpamodelgen.test.util.CompilationTest;
|
||||
import org.hibernate.jpamodelgen.test.util.TestForIssue;
|
||||
import org.hibernate.jpamodelgen.test.util.TestUtil;
|
||||
import org.hibernate.jpamodelgen.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertListAttributeTypeInMetaModelFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMapAttributesInMetaModelFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertSetAttributeTypeInMetaModelFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.*;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
|
@ -24,6 +22,7 @@ public class ElementCollectionTypeUseTest extends CompilationTest {
|
|||
@TestForIssue(jiraKey = "HHH-12612")
|
||||
@WithClasses(OfficeBuildingValidated.class)
|
||||
public void testAnnotatedCollectionElements() {
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( OfficeBuildingValidated.class ) );
|
||||
assertMetamodelClassGeneratedFor( OfficeBuildingValidated.class );
|
||||
|
||||
assertMapAttributesInMetaModelFor(
|
||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.jpamodelgen.test.elementcollection;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
/**
|
||||
|
@ -19,6 +21,7 @@ public class Homework {
|
|||
|
||||
private List<String> paths;
|
||||
|
||||
@ElementCollection
|
||||
public List<String> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
|
|
@ -14,13 +14,15 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.AccessType;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Entity @Access(AccessType.FIELD)
|
||||
public class OfficeBuildingValidated {
|
||||
|
||||
// mock a bean validation annotation using TYPE_USE
|
||||
|
|
|
@ -8,13 +8,11 @@ package org.hibernate.jpamodelgen.test.embeddable.generics;
|
|||
|
||||
import org.hibernate.jpamodelgen.test.util.CompilationTest;
|
||||
import org.hibernate.jpamodelgen.test.util.TestForIssue;
|
||||
import org.hibernate.jpamodelgen.test.util.TestUtil;
|
||||
import org.hibernate.jpamodelgen.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertSetAttributeTypeInMetaModelFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertSuperClassRelationShipInMetamodel;
|
||||
import static java.lang.System.out;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.*;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
|
@ -24,15 +22,16 @@ public class EmbeddableGenericsTest extends CompilationTest {
|
|||
@Test
|
||||
@WithClasses({ ChildEmbeddable.class, ParentEmbeddable.class })
|
||||
public void testGeneratingEmbeddablesWithGenerics() {
|
||||
out.println( getMetaModelSourceAsString(ParentEmbeddable.class) );
|
||||
assertMetamodelClassGeneratedFor( ChildEmbeddable.class );
|
||||
assertMetamodelClassGeneratedFor( ParentEmbeddable.class );
|
||||
|
||||
assertSetAttributeTypeInMetaModelFor(
|
||||
ParentEmbeddable.class,
|
||||
"fields",
|
||||
MyTypeInterface.class,
|
||||
"Expected Set<MyTypeInterface> for attribute named 'fields'"
|
||||
);
|
||||
// assertAttributeTypeInMetaModelFor(
|
||||
// ParentEmbeddable.class,
|
||||
// "fields",
|
||||
// "java.util.Set<? extends MyTypeInterface>",
|
||||
// "Expected Set for attribute named 'fields'"
|
||||
// );
|
||||
|
||||
assertSuperClassRelationShipInMetamodel(
|
||||
ChildEmbeddable.class,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package org.hibernate.jpamodelgen.test.generictype;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import org.hibernate.annotations.ManyToAny;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Generic<T extends Number> {
|
||||
@Id Long id;
|
||||
@ManyToOne Generic<T> parent;
|
||||
@OneToMany Set<Generic<T>> children;
|
||||
@ElementCollection List<T> list;
|
||||
@ElementCollection Map<T,T> map;
|
||||
@ManyToAny Set<T> set;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.test.generictype;
|
||||
|
||||
import org.hibernate.jpamodelgen.test.util.CompilationTest;
|
||||
import org.hibernate.jpamodelgen.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.lang.System.out;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.getMetaModelSourceAsString;
|
||||
|
||||
/**
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class GenericEntityTest extends CompilationTest {
|
||||
|
||||
@Test
|
||||
@WithClasses(Generic.class)
|
||||
public void testGeneric() {
|
||||
out.println( getMetaModelSourceAsString( Generic.class ) );
|
||||
assertMetamodelClassGeneratedFor( Generic.class );
|
||||
}
|
||||
}
|
|
@ -7,8 +7,6 @@
|
|||
package org.hibernate.jpamodelgen.test.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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.test.wildcard;
|
||||
|
||||
public interface Property<T> {
|
||||
|
||||
String getName();
|
||||
|
||||
T getValue();
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.hibernate.jpamodelgen.test.wildcard;
|
||||
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import org.hibernate.annotations.AnyDiscriminator;
|
||||
import org.hibernate.annotations.ManyToAny;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class PropertyRepo {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToAny
|
||||
@AnyDiscriminator(DiscriminatorType.STRING)
|
||||
private List<Property<?>> properties = new ArrayList<>();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.test.wildcard;
|
||||
|
||||
import org.hibernate.jpamodelgen.test.util.CompilationTest;
|
||||
import org.hibernate.jpamodelgen.test.util.TestUtil;
|
||||
import org.hibernate.jpamodelgen.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class WildcardTest extends CompilationTest {
|
||||
@Test
|
||||
@WithClasses({ PropertyRepo.class })
|
||||
public void testGeneratedAnnotationNotGenerated() {
|
||||
System.out.println( TestUtil.getMetaModelSourceAsString( PropertyRepo.class ) );
|
||||
assertMetamodelClassGeneratedFor( PropertyRepo.class );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue