HHH-18829 Main:
- Hibernate Processor - create ID class in meta data class if entity class with more than one ID component is not annotated with @IdClass; property order must be preserved - Hibernate Core - if entity class has more than one ID component, but is not annotated with @IdClass entity binder should try to use ID class from metamodel if generated
This commit is contained in:
parent
b9351cffc6
commit
445f95fb62
|
@ -481,10 +481,22 @@ public class EntityBinder {
|
||||||
final ClassDetails classWithIdClass = inheritanceState.getClassWithIdClass( false );
|
final ClassDetails classWithIdClass = inheritanceState.getClassWithIdClass( false );
|
||||||
if ( classWithIdClass != null ) {
|
if ( classWithIdClass != null ) {
|
||||||
final IdClass idClassAnn = classWithIdClass.getDirectAnnotationUsage( IdClass.class );
|
final IdClass idClassAnn = classWithIdClass.getDirectAnnotationUsage( IdClass.class );
|
||||||
|
final ClassDetails compositeClass;
|
||||||
|
if ( idClassAnn == null ) {
|
||||||
|
try {
|
||||||
|
compositeClass = getMetadataCollector().getSourceModelBuildingContext()
|
||||||
|
.getClassDetailsRegistry()
|
||||||
|
.resolveClassDetails( inheritanceState.getClassDetails().getClassName() + "_$Id" );
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
final Class<?> idClassValue = idClassAnn.value();
|
final Class<?> idClassValue = idClassAnn.value();
|
||||||
final ClassDetails compositeClass =
|
compositeClass = getMetadataCollector().getSourceModelBuildingContext()
|
||||||
getMetadataCollector().getSourceModelBuildingContext().getClassDetailsRegistry()
|
.getClassDetailsRegistry().resolveClassDetails( idClassValue.getName() );
|
||||||
.resolveClassDetails( idClassValue.getName() );
|
}
|
||||||
final TypeDetails compositeType = new ClassTypeDetailsImpl( compositeClass, TypeDetails.Kind.CLASS );
|
final TypeDetails compositeType = new ClassTypeDetailsImpl( compositeClass, TypeDetails.Kind.CLASS );
|
||||||
final TypeDetails classWithIdType = new ClassTypeDetailsImpl( classWithIdClass, TypeDetails.Kind.CLASS );
|
final TypeDetails classWithIdType = new ClassTypeDetailsImpl( classWithIdClass, TypeDetails.Kind.CLASS );
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.hibernate.boot.model.internal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.boot.spi.AccessType;
|
import org.hibernate.boot.spi.AccessType;
|
||||||
|
@ -183,6 +184,13 @@ public class InheritanceState {
|
||||||
return classDetails;
|
return classDetails;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
final long count = Stream.concat(
|
||||||
|
classDetails.getFields().stream(),
|
||||||
|
classDetails.getMethods().stream()
|
||||||
|
).filter( t -> t.hasDirectAnnotationUsage( Id.class ) ).count();
|
||||||
|
if ( count > 1 ) {
|
||||||
|
return classDetails;
|
||||||
|
}
|
||||||
final InheritanceState state = getSuperclassInheritanceState( classDetails, inheritanceStatePerClass );
|
final InheritanceState state = getSuperclassInheritanceState( classDetails, inheritanceStatePerClass );
|
||||||
if ( state != null ) {
|
if ( state != null ) {
|
||||||
return state.getClassWithIdClass( true );
|
return state.getClassWithIdClass( true );
|
||||||
|
|
|
@ -108,6 +108,8 @@ import static org.hibernate.processor.util.TypeUtils.propertyName;
|
||||||
*/
|
*/
|
||||||
public class AnnotationMetaEntity extends AnnotationMeta {
|
public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
|
|
||||||
|
private static final String ID_CLASS_MEMBER_NAME = "<ID_CLASS>";
|
||||||
|
|
||||||
private final ImportContext importContext;
|
private final ImportContext importContext;
|
||||||
private final TypeElement element;
|
private final TypeElement element;
|
||||||
private final Map<String, MetaAttribute> members;
|
private final Map<String, MetaAttribute> members;
|
||||||
|
@ -438,6 +440,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
|
|
||||||
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
||||||
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );
|
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );
|
||||||
|
|
||||||
|
addIdClassIfNeeded( fieldsOfClass, gettersAndSettersOfClass );
|
||||||
}
|
}
|
||||||
|
|
||||||
addAuxiliaryMembers();
|
addAuxiliaryMembers();
|
||||||
|
@ -451,6 +455,33 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addIdClassIfNeeded(List<? extends Element> fields, List<? extends Element> methods) {
|
||||||
|
if ( hasAnnotation( element, ID_CLASS ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final List<MetaAttribute> components = new ArrayList<>();
|
||||||
|
for ( Element field : fields ) {
|
||||||
|
if ( hasAnnotation( field, ID ) && isPersistent( field, AccessType.FIELD ) ) {
|
||||||
|
final String propertyName = propertyName( this, field );
|
||||||
|
if ( members.containsKey( propertyName ) ) {
|
||||||
|
components.add( members.get( propertyName ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( Element method : methods ) {
|
||||||
|
if ( hasAnnotation( method, ID ) && isPersistent( method, AccessType.PROPERTY ) ) {
|
||||||
|
final String propertyName = propertyName( this, method );
|
||||||
|
if ( members.containsKey( propertyName ) ) {
|
||||||
|
components.add( members.get( propertyName ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( components.size() < 2 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
putMember( ID_CLASS_MEMBER_NAME, new IdClassMetaAttribute( this, components ) );
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkEntities(List<ExecutableElement> lifecycleMethods) {
|
private boolean checkEntities(List<ExecutableElement> lifecycleMethods) {
|
||||||
boolean foundPersistenceEntity = false;
|
boolean foundPersistenceEntity = false;
|
||||||
VariableElement nonPersistenceParameter = null;
|
VariableElement nonPersistenceParameter = null;
|
||||||
|
|
|
@ -4,11 +4,15 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.processor.annotation;
|
package org.hibernate.processor.annotation;
|
||||||
|
|
||||||
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import org.hibernate.processor.model.MetaSingleAttribute;
|
import org.hibernate.processor.model.MetaSingleAttribute;
|
||||||
import org.hibernate.processor.util.Constants;
|
import org.hibernate.processor.util.Constants;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Max Andersen
|
* @author Max Andersen
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
|
@ -24,4 +28,9 @@ public class AnnotationMetaSingleAttribute extends AnnotationMetaAttribute imple
|
||||||
public final String getMetaType() {
|
public final String getMetaType() {
|
||||||
return Constants.SINGULAR_ATTRIBUTE;
|
return Constants.SINGULAR_ATTRIBUTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AnnotationMirror> inheritedAnnotations() {
|
||||||
|
return new ArrayList<>(element.getAnnotationMirrors());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.processor.annotation;
|
||||||
|
|
||||||
|
import org.hibernate.processor.model.MetaAttribute;
|
||||||
|
import org.hibernate.processor.model.Metamodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IdClassMetaAttribute implements MetaAttribute {
|
||||||
|
|
||||||
|
private final Metamodel parent;
|
||||||
|
|
||||||
|
private final List<MetaAttribute> components;
|
||||||
|
|
||||||
|
public IdClassMetaAttribute(Metamodel parent, List<MetaAttribute> components) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.components = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasTypedAttribute() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStringAttribute() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeDeclarationString() {
|
||||||
|
final StringBuilder decl = new StringBuilder()
|
||||||
|
.append("\n/**\n * Static ID class for {@link ")
|
||||||
|
.append( parent.getQualifiedName() )
|
||||||
|
.append( "}\n **/\n" )
|
||||||
|
.append( "public record Id" );
|
||||||
|
String delimiter = "(";
|
||||||
|
for ( MetaAttribute component : components ) {
|
||||||
|
decl.append( delimiter ).append( parent.importType( component.getTypeDeclaration() ) )
|
||||||
|
.append( ' ' ).append( component.getPropertyName() );
|
||||||
|
delimiter = ", ";
|
||||||
|
}
|
||||||
|
return decl.append( ") {}" ).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeNameDeclarationString() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMetaType() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPropertyName() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTypeDeclaration() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Metamodel getHostingEntity() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue