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 );
|
||||
if ( classWithIdClass != null ) {
|
||||
final IdClass idClassAnn = classWithIdClass.getDirectAnnotationUsage( IdClass.class );
|
||||
final Class<?> idClassValue = idClassAnn.value();
|
||||
final ClassDetails compositeClass =
|
||||
getMetadataCollector().getSourceModelBuildingContext().getClassDetailsRegistry()
|
||||
.resolveClassDetails( idClassValue.getName() );
|
||||
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();
|
||||
compositeClass = getMetadataCollector().getSourceModelBuildingContext()
|
||||
.getClassDetailsRegistry().resolveClassDetails( idClassValue.getName() );
|
||||
}
|
||||
final TypeDetails compositeType = new ClassTypeDetailsImpl( compositeClass, 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.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.boot.spi.AccessType;
|
||||
|
@ -183,6 +184,13 @@ public class InheritanceState {
|
|||
return classDetails;
|
||||
}
|
||||
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 );
|
||||
if ( state != null ) {
|
||||
return state.getClassWithIdClass( true );
|
||||
|
|
|
@ -108,6 +108,8 @@ import static org.hibernate.processor.util.TypeUtils.propertyName;
|
|||
*/
|
||||
public class AnnotationMetaEntity extends AnnotationMeta {
|
||||
|
||||
private static final String ID_CLASS_MEMBER_NAME = "<ID_CLASS>";
|
||||
|
||||
private final ImportContext importContext;
|
||||
private final TypeElement element;
|
||||
private final Map<String, MetaAttribute> members;
|
||||
|
@ -438,6 +440,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
||||
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );
|
||||
|
||||
addIdClassIfNeeded( fieldsOfClass, gettersAndSettersOfClass );
|
||||
}
|
||||
|
||||
addAuxiliaryMembers();
|
||||
|
@ -451,6 +455,33 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
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) {
|
||||
boolean foundPersistenceEntity = false;
|
||||
VariableElement nonPersistenceParameter = null;
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
*/
|
||||
package org.hibernate.processor.annotation;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
import org.hibernate.processor.model.MetaSingleAttribute;
|
||||
import org.hibernate.processor.util.Constants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Max Andersen
|
||||
* @author Hardy Ferentschik
|
||||
|
@ -24,4 +28,9 @@ public class AnnotationMetaSingleAttribute extends AnnotationMetaAttribute imple
|
|||
public final String getMetaType() {
|
||||
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