Skip to content

Commit

Permalink
sebersole#25 - Create AnnotationUsage for named-entity-graph in XML
Browse files Browse the repository at this point in the history
  • Loading branch information
dreab8 committed Dec 4, 2023
1 parent b7e7b77 commit d14b856
Show file tree
Hide file tree
Showing 4 changed files with 316 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.hibernate.boot.jaxb.mapping.spi.JaxbIdImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbManagedType;
import org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclassImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedEntityGraphImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOneImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute;
import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute;
Expand Down Expand Up @@ -59,6 +60,7 @@
import jakarta.persistence.AccessType;
import jakarta.persistence.Embeddable;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.NamedEntityGraph;

import static org.hibernate.internal.util.NullnessHelper.coalesce;
import static org.hibernate.internal.util.NullnessHelper.nullif;
Expand Down Expand Up @@ -475,6 +477,11 @@ private static void processEntityMetadata(

applyTenantId( classDetails, jaxbEntity, classAccessType, xmlDocumentContext );

final List<JaxbNamedEntityGraphImpl> namedEntityGraphs = jaxbEntity.getNamedEntityGraphs();
for ( JaxbNamedEntityGraphImpl namedEntityGraph : namedEntityGraphs ) {
XmlAnnotationHelper.applyNamedEntityGraph( namedEntityGraph, classDetails, xmlDocumentContext );
}

// todo : secondary-tables
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
import org.hibernate.boot.jaxb.mapping.spi.JaxbLobImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyColumnImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyJoinColumnImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedAttributeNodeImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedEntityGraphImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedSubgraphImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbNationalizedImpl;
import org.hibernate.boot.jaxb.mapping.spi.JaxbNaturalId;
import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGeneratorImpl;
Expand Down Expand Up @@ -125,6 +128,9 @@
import jakarta.persistence.Lob;
import jakarta.persistence.MapKeyColumn;
import jakarta.persistence.MapKeyJoinColumn;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedSubgraph;
import jakarta.persistence.PostLoad;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostRemove;
Expand Down Expand Up @@ -1352,4 +1358,142 @@ private static String prefixIfNotAlready(String value, String prefix) {
}
return value;
}

static void applyNamedEntityGraph(
JaxbNamedEntityGraphImpl namedEntityGraph,
MutableClassDetails target,
XmlDocumentContext xmlDocumentContext) {
if ( namedEntityGraph != null ) {
final MutableAnnotationUsage<NamedEntityGraph> namedEntityGraphAnn = XmlProcessingHelper.getOrMakeAnnotation(
NamedEntityGraph.class,
target,
xmlDocumentContext
);

final AnnotationDescriptor<NamedEntityGraph> namedEntityGraphAnnotationDescriptor = namedEntityGraphAnn.getAnnotationDescriptor();
applyOr(
namedEntityGraph,
JaxbNamedEntityGraphImpl::getName,
"name",
namedEntityGraphAnn,
namedEntityGraphAnnotationDescriptor
);

applyOr(
namedEntityGraph,
JaxbNamedEntityGraphImpl::isIncludeAllAttributes,
"includeAllAttributes",
namedEntityGraphAnn,
namedEntityGraphAnnotationDescriptor
);

namedEntityGraphAnn.setAttributeValue(
"attributeNodes",
makeNamedAttributeNodes( namedEntityGraph.getNamedAttributeNode(), target, xmlDocumentContext )
);

namedEntityGraphAnn.setAttributeValue(
"subgraphs",
makeNamedSubgraphs(
target,
xmlDocumentContext,
namedEntityGraph.getSubgraph()
)
);

namedEntityGraphAnn.setAttributeValue(
"subclassSubgraphs",
makeNamedSubgraphs(
target,
xmlDocumentContext,
namedEntityGraph.getSubclassSubgraph()
)
);

}

}

private static List<MutableAnnotationUsage<NamedSubgraph>> makeNamedSubgraphs(
MutableClassDetails target,
XmlDocumentContext xmlDocumentContext,
List<JaxbNamedSubgraphImpl> subclassSubgraphNodes) {
final List<MutableAnnotationUsage<NamedSubgraph>> subgraphAnnotations =
new ArrayList<>( subclassSubgraphNodes.size() );
for ( JaxbNamedSubgraphImpl subclassSubgraphNode : subclassSubgraphNodes ) {
final String subGraphsNodeName = subclassSubgraphNode.getName();
final MutableAnnotationUsage<NamedSubgraph> namedSubgraphNodeAnn = XmlProcessingHelper.getOrMakeNamedAnnotation(
NamedSubgraph.class,
subGraphsNodeName,
target,
xmlDocumentContext
);
applyAttributeIfSpecified( namedSubgraphNodeAnn, "name", subGraphsNodeName );

final String clazz = subclassSubgraphNode.getClazz();
if ( clazz == null ) {
namedSubgraphNodeAnn.setAttributeValue(
"type",
resolveJavaType(
namedSubgraphNodeAnn.getAnnotationDescriptor()
.getAttribute( "type" )
.getAttributeMethod()
.getDefaultValue().toString(),
xmlDocumentContext
)
);
}
else {
namedSubgraphNodeAnn.setAttributeValue(
"type",
resolveJavaType( subclassSubgraphNode.getClazz(), xmlDocumentContext )

);
}
namedSubgraphNodeAnn.setAttributeValue(
"attributeNodes",
makeNamedAttributeNodes( subclassSubgraphNode.getNamedAttributeNode(), target, xmlDocumentContext )
);

subgraphAnnotations.add( namedSubgraphNodeAnn );
}
return subgraphAnnotations;
}

private static List<MutableAnnotationUsage<NamedAttributeNode>> makeNamedAttributeNodes(
List<JaxbNamedAttributeNodeImpl> namedAttributeNodes,
MutableClassDetails target,
XmlDocumentContext xmlDocumentContext) {
final List<MutableAnnotationUsage<NamedAttributeNode>> namedAttributeNodeAnnotations =
new ArrayList<>( namedAttributeNodes.size() );
for ( JaxbNamedAttributeNodeImpl namedAttributeNode : namedAttributeNodes ) {
final MutableAnnotationUsage<NamedAttributeNode> namedAttributeNodeAnn = XmlProcessingHelper.makeNestedAnnotation(
NamedAttributeNode.class,
target,
xmlDocumentContext
);
applyAttributeIfSpecified( namedAttributeNodeAnn, "value", namedAttributeNode.getName() );
final AnnotationDescriptor<NamedAttributeNode> namedAttributeNodeDescriptor = xmlDocumentContext
.getModelBuildingContext()
.getAnnotationDescriptorRegistry()
.getDescriptor( NamedAttributeNode.class );
applyOr(
namedAttributeNode,
JaxbNamedAttributeNodeImpl::getSubgraph,
"subgraph",
namedAttributeNodeAnn,
namedAttributeNodeDescriptor
);
applyOr(
namedAttributeNode,
JaxbNamedAttributeNodeImpl::getKeySubgraph,
"keySubgraph",
namedAttributeNodeAnn,
namedAttributeNodeDescriptor
);
namedAttributeNodeAnnotations.add( namedAttributeNodeAnn );

}
return namedAttributeNodeAnnotations;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package org.hibernate.models.orm.xml.dynamic;

import java.util.List;
import java.util.Set;

import org.hibernate.boot.internal.BootstrapContextImpl;
import org.hibernate.boot.internal.MetadataBuilderImpl;
import org.hibernate.boot.model.process.spi.ManagedResources;
import org.hibernate.boot.models.categorize.spi.CategorizedDomainModel;
import org.hibernate.boot.models.categorize.spi.EntityHierarchy;
import org.hibernate.boot.models.categorize.spi.EntityTypeMetadata;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.models.orm.process.ManagedResourcesImpl;
import org.hibernate.models.spi.AnnotationUsage;
import org.hibernate.models.spi.ClassDetails;

import org.junit.jupiter.api.Test;

import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedSubgraph;

import static org.assertj.core.api.Assertions.assertThat;
import static org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor.processManagedResources;

public class NamedEntityGraphTest {
@Test
void testNamedEntityGraph() {
final ManagedResources managedResources = new ManagedResourcesImpl.Builder()
.addXmlMappings( "mappings/dynamic/dynamic-named-entity-graph.xml" )
.build();
try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) {
final BootstrapContextImpl bootstrapContext = new BootstrapContextImpl(
serviceRegistry,
new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry )
);
final CategorizedDomainModel categorizedDomainModel = processManagedResources(
managedResources,
bootstrapContext
);

final Set<EntityHierarchy> entityHierarchies = categorizedDomainModel.getEntityHierarchies();
assertThat( entityHierarchies ).hasSize( 1 );

entityHierarchies.forEach(
entityHierarchy -> {
final EntityTypeMetadata root = entityHierarchy.getRoot();
final String entityName = root.getEntityName();

final AnnotationUsage<NamedEntityGraph> namedEntityGraphAnnotationUsage = root.getClassDetails()
.getAnnotationUsage( NamedEntityGraph.class );

if ( entityName.equals( "Address" ) ) {
assertThat( namedEntityGraphAnnotationUsage ).isNull();
}
else {
assertThat( namedEntityGraphAnnotationUsage ).isNotNull();

final String graphName = namedEntityGraphAnnotationUsage.getAttributeValue( "name" );
assertThat( graphName ).isEqualTo( "employee" );

final boolean includeAllAttributes = namedEntityGraphAnnotationUsage.getAttributeValue(
"includeAllAttributes" );
assertThat( includeAllAttributes ).isTrue();

List<AnnotationUsage<NamedAttributeNode>> namedAttributeNodeUsage = namedEntityGraphAnnotationUsage
.getAttributeValue( "attributeNodes" );
assertThat( namedAttributeNodeUsage ).size().isEqualTo( 2 );

// check NamedEntityGraph attributeNodes

AnnotationUsage<NamedAttributeNode> firstAttributeNode = namedAttributeNodeUsage.get( 0 );
checkAttributeNode( firstAttributeNode, "name", "", "" );

AnnotationUsage<NamedAttributeNode> secondAttributeNode = namedAttributeNodeUsage.get( 1 );
checkAttributeNode( secondAttributeNode, "address", "employee.address", "" );

// check NamedEntityGraph subgraphs
final List<AnnotationUsage<NamedSubgraph>> subgraphUsages = namedEntityGraphAnnotationUsage
.getAttributeValue( "subgraphs" );
assertThat( subgraphUsages ).size().isEqualTo( 2 );

AnnotationUsage<NamedSubgraph> firstSubgraph = subgraphUsages.get( 0 );
assertThat( firstSubgraph.getString( "name" ) ).isEqualTo( "first.subgraph" );
assertThat( firstSubgraph.<ClassDetails>getAttributeValue( "type" ).getName() )
.isEqualTo( void.class.getName() );

// check first NamedSubgraph attributeNodes

namedAttributeNodeUsage = firstSubgraph.getAttributeValue( "attributeNodes" );
assertThat( namedAttributeNodeUsage ).size().isEqualTo( 1 );

checkAttributeNode( namedAttributeNodeUsage.get( 0 ), "city", "", "" );

AnnotationUsage<NamedSubgraph> secondSubgraph = subgraphUsages.get( 1 );
assertThat( secondSubgraph.getString( "name" ) ).isEqualTo( "second.subgraph" );
assertThat( secondSubgraph.<ClassDetails>getAttributeValue( "type" ).getName() )
.isEqualTo( String.class.getName() );

namedAttributeNodeUsage = secondSubgraph.getAttributeValue( "attributeNodes" );
assertThat( namedAttributeNodeUsage ).size().isEqualTo( 3 );

// check second NamedSubgraph attributeNodes
checkAttributeNode( namedAttributeNodeUsage.get( 0 ), "city", "sub1", "" );
checkAttributeNode( namedAttributeNodeUsage.get( 1 ), "name", "sub", "" );
checkAttributeNode( namedAttributeNodeUsage.get( 2 ), "surname", "", "" );


final List<AnnotationUsage<NamedSubgraph>> subClassSubgraphUsages = namedEntityGraphAnnotationUsage
.getAttributeValue( "subclassSubgraphs" );
assertThat( subClassSubgraphUsages ).size().isEqualTo( 0 );

}
}
);
}
}

private static void checkAttributeNode(
AnnotationUsage<NamedAttributeNode> firstAttributeNode,
String expectedValueName,
String expectedSubgraph,
String expectedKeySubgraph) {
assertThat( firstAttributeNode.getString( "value" ) ).isEqualTo( expectedValueName );
assertThat( firstAttributeNode.getString( "subgraph" ) ).isEqualTo( expectedSubgraph );
assertThat( firstAttributeNode.getString( "keySubgraph" ) ).isEqualTo( expectedKeySubgraph );
}
}
36 changes: 36 additions & 0 deletions src/test/resources/mappings/dynamic/dynamic-named-entity-graph.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ SPDX-License-Identifier: Apache-2.0
~ Copyright: Red Hat Inc. and Hibernate Authors
-->
<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping"
version="3.2">
<entity name="Employee" metadata-complete="true">
<named-entity-graph name="employee" include-all-attributes="true">
<named-attribute-node name="name"/>
<named-attribute-node name="address" subgraph="employee.address"/>
<subgraph name="first.subgraph">
<named-attribute-node name="city"/>
</subgraph>
<subgraph name="second.subgraph" class="String">
<named-attribute-node name="city" subgraph="sub1"/>
<named-attribute-node name="name" subgraph="sub"/>
<named-attribute-node name="surname" />
</subgraph>
</named-entity-graph>
<attributes>
<id name="id"/>
<basic name="name"/>
<basic name="surname"/>
<!-- <one-to-one name="address" fetch="LAZY"/>-->
</attributes>
</entity>
<!-- <entity name="Address" metadata-complete="true">-->
<!-- <attributes>-->
<!-- <id name="id"/>-->
<!-- <basic name="city"/>-->

<!-- </attributes>-->
<!-- </entity>-->
</entity-mappings>

0 comments on commit d14b856

Please sign in to comment.