Skip to content

Commit

Permalink
jakartaee/persistence#454 - removeAttributeNodes(Attribute.Persistent…
Browse files Browse the repository at this point in the history
…AttributeType) in Graph

Signed-off-by: Tomáš Kraus <[email protected]>
  • Loading branch information
Tomas-Kraus committed Dec 19, 2023
1 parent f904fcb commit 07f99f3
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.tests.jpa.persistence32;

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

import jakarta.persistence.AttributeNode;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceUnitUtil;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.ManagedType;
import junit.framework.Test;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.testing.models.jpa.persistence32.Pokemon;

/**
* Verify jakarta.persistence 3.2 API changes in {@link EntityGraph}.
*/
public class EntityGraphTest extends AbstractPokemon {

// Pokemons. Array index is ID value.
// Value of ID = 0 does not exist so it's array instance is set to null.
static final Pokemon[] POKEMONS = new Pokemon[] {
null, // Skip array index 0
new Pokemon(1, "Pidgey", List.of(TYPES[1], TYPES[3])),
new Pokemon(2, "Beedrill", List.of(TYPES[7], TYPES[4])),
new Pokemon(3, "Squirtle", List.of(TYPES[11])),
new Pokemon(4, "Caterpie", List.of(TYPES[7]))
};

public static Test suite() {
return suite(
"EntityGraphTest",
new EntityGraphTest("testRemoveAttributeNodesByPersistentAttributeType")
);
}

public EntityGraphTest() {
}

public EntityGraphTest(String name) {
super(name);
setPuName(getPersistenceUnitName());
}

// Initialize data
@Override
protected void suiteSetUp() {
super.suiteSetUp();
emf.runInTransaction(em -> {
for (int i = 1; i < POKEMONS.length; i++) {
em.persist(POKEMONS[i]);
}
});

}

// Test removeAttributeNodes(Attribute.PersistentAttributeType)
// This also tests addAttributeNode(Attribute<? super X, Y>), addAttributeNode(String)
// and removeAttributeNode(Attribute<? super X, ?>)
public void testRemoveAttributeNodesByPersistentAttributeType() {
try (EntityManager em = emf.createEntityManager()) {
EntityGraph<Pokemon> pokemonGraph = em.createEntityGraph(Pokemon.class);
ManagedType<Pokemon> managedType = emf.getMetamodel().managedType(Pokemon.class);
pokemonGraph.addAttributeNode(managedType.getAttribute("id"));
pokemonGraph.addAttributeNode(managedType.getAttribute("name"));
pokemonGraph.addSubgraph("types").addAttributeNode("name");
pokemonGraph.addSubgraph("trainer").addAttributeNode("name");
pokemonGraph.removeAttributeNodes(Attribute.PersistentAttributeType.MANY_TO_ONE);
// Trainer node, which is many-to-one, shall be gone now. Verify nodes content.
List<AttributeNode<?>> nodes = pokemonGraph.getAttributeNodes();
Set<String> checkNodes = new HashSet<>(List.of("id", "name", "types"));
assertEquals(3, nodes.size());
for (AttributeNode<?> node : nodes) {
if (checkNodes.contains(node.getAttributeName())) {
checkNodes.remove(node.getAttributeName());
} else {
fail(String.format("Node %s was not found in the EntityGraph.", node.getAttributeName()));
}
}
assertTrue(checkNodes.isEmpty());
// Verify attributes load status with database query
PersistenceUnitUtil util = em.getEntityManagerFactory().getPersistenceUnitUtil();
Pokemon pokemon = em.createQuery("SELECT p FROM Pokemon p WHERE p.id = :id", Pokemon.class)
.setParameter("id", POKEMONS[1].getId())
.setHint(QueryHints.JPA_FETCH_GRAPH, pokemonGraph)
.getSingleResult();
assertTrue("Attribute id is present in EntityGraph but not in result", util.isLoaded(pokemon, "id"));
assertTrue("Attribute name is present in EntityGraph but not in result", util.isLoaded(pokemon, "name"));
pokemon.getTypes().stream().findFirst().ifPresent(
type -> assertTrue("Attribute types is present in EntityGraph but not in result", util.isLoaded(type, "name")));
assertFalse("Attribute trainer is not present in EntityGraph but is present in result", util.isLoaded(pokemon.getTrainer(), "name"));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
package org.eclipse.persistence.testing.tests.jpa.persistence32;

import java.util.List;
import java.util.Map;

import jakarta.persistence.NoResultException;
import jakarta.persistence.NonUniqueResultException;
Expand Down Expand Up @@ -47,8 +46,6 @@ public static Test suite() {
);
}

Map<Integer, Pokemon> pokemons = null;

public QueryTest() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import jakarta.persistence.Subgraph;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.persistence.metamodel.PluralAttribute;

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
Expand All @@ -53,25 +53,30 @@ public class EntityGraphImpl<X> extends AttributeNodeImpl<X> implements EntityGr

protected Map<String, AttributeNodeImpl<?>> attributeNodes;

protected EntityGraphImpl(AttributeGroup group, ClassDescriptor descriptor) {
private final Metamodel metamodel;

protected EntityGraphImpl(AttributeGroup group, Metamodel metamodel, ClassDescriptor descriptor) {
super();
this.attributeGroup = group;
this.classType = descriptor.getJavaClass();
this.isMutable = true;
this.descriptor = descriptor;
this.metamodel = metamodel;
}

public EntityGraphImpl(AttributeGroup group) {
@SuppressWarnings("unchecked")
public EntityGraphImpl(AttributeGroup group, Metamodel metamodel) {
super();
this.attributeGroup = group;
this.classType = (Class<X>) group.getType();
if (this.classType == null){
this.classType = (Class<X>) CoreClassConstants.OBJECT;
}
this.metamodel = metamodel;
}

protected EntityGraphImpl(AttributeGroup group, ClassDescriptor descriptor, String attribute) {
this(group, descriptor);
protected EntityGraphImpl(AttributeGroup group, Metamodel metamodel, ClassDescriptor descriptor, String attribute) {
this(group, metamodel, descriptor);
this.currentAttribute = attribute;
}

Expand Down Expand Up @@ -152,10 +157,13 @@ public void removeAttributeNode(Attribute<? super X, ?> attribute) {
removeAttributeNodeImpl(attribute.getName());
}

// TODO-API-3.2
@Override
public void removeAttributeNodes(Attribute.PersistentAttributeType nodeTypes) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
for (Attribute<? super X, ?> attribute : metamodel.managedType(classType).getAttributes()) {
if (attribute.getPersistentAttributeType() == nodeTypes) {
removeAttributeNode(attribute);
}
}
}

// Add an attribute node of given name to the entity graph.
Expand All @@ -167,8 +175,8 @@ private <Y> AttributeNode<Y> addAttributeNodeImpl(String attributeName) {
new Object[] {attributeName, this.getClassType()}));
}
AttributeNodeImpl<Y> attributeNode = new AttributeNodeImpl<>(attributeName);
// Order is important here, must add attribute node to node list before adding to group, or it will appear in node list twice.
addAttributeNodeImpl(attributeNode);
//order is important here, must add attribute node to node list before adding to group or it will appear in node list twice.
attributeGroup.addAttribute(attributeName, (AttributeGroup) null);
return attributeNode;
}
Expand Down Expand Up @@ -211,7 +219,7 @@ public <S extends X> Subgraph<S> addTreatedSubgraph(Class<S> type) {
this.attributeGroup.getSubClassGroups().put(type, subGroup);
subGroup.setAllSubclasses(this.attributeGroup.getSubClassGroups());
this.attributeGroup.insertSubClass(subGroup);
return new EntityGraphImpl<>(subGroup, targetDesc);
return new EntityGraphImpl<>(subGroup, metamodel, targetDesc);
}

@Override
Expand All @@ -232,21 +240,21 @@ public <T> Subgraph<? extends T> addSubgraph(Attribute<? super X, T> attribute,
}

@Override
public <X> Subgraph<X> addSubgraph(String attributeName) {
public <T> Subgraph<T> addSubgraph(String attributeName) {
return this.addSubgraph(attributeName, null);
}

@Override
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
public <T> Subgraph<T> addSubgraph(String attributeName, Class<T> type) {
if (!this.isMutable) {
throw new IllegalStateException(ExceptionLocalization.buildMessage("immutable_entitygraph"));
}
AttributeNodeImpl node = null;
AttributeNodeImpl<?> node = null;
if (this.attributeNodes != null){
node = this.attributeNodes.get(attributeName);
}
if (node == null){
node = new AttributeNodeImpl<X>(attributeName);
node = new AttributeNodeImpl<T>(attributeName);
addAttributeNodeImpl(node);
}
AttributeGroup localGroup = null;
Expand All @@ -264,7 +272,7 @@ public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("type_unkown_for_this_attribute", new Object[] { type.getName(), attributeName }));
}
}
EntityGraphImpl entityGraph = new EntityGraphImpl(localGroup, targetDesc, attributeName);
EntityGraphImpl<T> entityGraph = new EntityGraphImpl<>(localGroup, metamodel, targetDesc, attributeName);
node.addSubgraph(entityGraph);
//order is important here, must add entity graph to node list before adding to group or it will appear in node list twice.
this.attributeGroup.addAttribute(attributeName, localGroup);
Expand Down Expand Up @@ -321,21 +329,21 @@ public <T> Subgraph<? extends T> addKeySubgraph(Attribute<? super X, T> attribut
}

@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
public <T> Subgraph<T> addKeySubgraph(String attributeName) {
return this.addKeySubgraph(attributeName, null);
}

@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
public <T> Subgraph<T> addKeySubgraph(String attributeName, Class<T> type) {
if (!this.isMutable) {
throw new IllegalStateException(ExceptionLocalization.buildMessage("immutable_entitygraph"));
}
AttributeNodeImpl node = null;
AttributeNodeImpl<?> node = null;
if (this.attributeNodes != null){
node = this.attributeNodes.get(attributeName);
}
if (node == null){
node = new AttributeNodeImpl<X>(attributeName);
node = new AttributeNodeImpl<>(attributeName);
addAttributeNodeImpl(node);
}
AttributeGroup localGroup = null;
Expand All @@ -356,7 +364,7 @@ public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("type_unkown_for_this_attribute", new Object[] { type.getName(), attributeName }));
}
}
EntityGraphImpl entityGraph = new EntityGraphImpl(localGroup, targetDesc, attributeName);
EntityGraphImpl<T> entityGraph = new EntityGraphImpl<>(localGroup, metamodel, targetDesc, attributeName);
node.addKeySubgraph(entityGraph);
//order is important here, must add entity graph to node list before adding to group or it will appear in node list twice.
this.attributeGroup.addAttributeKey(attributeName, localGroup);
Expand All @@ -368,7 +376,7 @@ public List<AttributeNode<?>> getAttributeNodes() {
if (this.attributeNodes == null) {
buildAttributeNodes();
}
return new ArrayList(this.attributeNodes.values());
return new ArrayList<>(this.attributeNodes.values());
}

@Override
Expand Down Expand Up @@ -408,9 +416,9 @@ protected void buildAttributeNodes() {
if (!type.equals(CoreClassConstants.OBJECT) && localDescriptor.hasInheritance()) {
localDescriptor = localDescriptor.getInheritancePolicy().getDescriptor(type);
}
node.addSubgraph(new EntityGraphImpl<>(subGroup, localDescriptor));
node.addSubgraph(new EntityGraphImpl<>(subGroup, metamodel, localDescriptor));
} else {
node.addSubgraph(new EntityGraphImpl<>(subGroup));
node.addSubgraph(new EntityGraphImpl<>(subGroup, metamodel));
}

}
Expand All @@ -425,9 +433,9 @@ protected void buildAttributeNodes() {
if (!type.equals(CoreClassConstants.OBJECT) && localDescriptor.hasInheritance()) {
localDescriptor = localDescriptor.getInheritancePolicy().getDescriptor(type);
}
node.addKeySubgraph(new EntityGraphImpl<>(subGroup, localDescriptor));
node.addKeySubgraph(new EntityGraphImpl<>(subGroup, metamodel, localDescriptor));
} else {
node.addKeySubgraph(new EntityGraphImpl<>(subGroup));
node.addKeySubgraph(new EntityGraphImpl<>(subGroup, metamodel));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,6 @@ public PersistenceUnitTransactionType getTransactionType() {
return delegate.getTransactionType();
}

// TODO-API-3.2
@Override
public SchemaManager getSchemaManager() {
return delegate.getSchemaManager();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3165,26 +3165,26 @@ public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
if (descriptor == null || descriptor.isAggregateDescriptor()){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("unknown_bean_class", new Object[]{rootType.getName()}));
}
return new EntityGraphImpl<T>(new AttributeGroup(null, rootType, true), descriptor);
return new EntityGraphImpl<>(new AttributeGroup(null, rootType, true), factory.getMetamodel(), descriptor);
}

@Override
public EntityGraph createEntityGraph(String graphName) {
public EntityGraph<?> createEntityGraph(String graphName) {
AttributeGroup group = this.getAbstractSession().getAttributeGroups().get(graphName);
if (group == null){
return null;
}
ClassDescriptor descriptor = this.getAbstractSession().getDescriptor(group.getType());
return new EntityGraphImpl(group.clone(), descriptor);
return new EntityGraphImpl<>(group.clone(), factory.getMetamodel(), descriptor);
}

@Override
public EntityGraph getEntityGraph(String graphName) {
public EntityGraph<?> getEntityGraph(String graphName) {
AttributeGroup group = this.getAbstractSession().getAttributeGroups().get(graphName);
if (group == null){
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("no_entity_graph_of_name", new Object[]{graphName}));
}
return new EntityGraphImpl(group);
return new EntityGraphImpl<>(group, factory.getMetamodel());
}

@Override
Expand All @@ -3195,13 +3195,13 @@ public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
}
List<EntityGraph<? super T>> result = new ArrayList<EntityGraph<? super T>>();
for (AttributeGroup group : descriptor.getAttributeGroups().values()){
result.add(new EntityGraphImpl<>(group));
result.add(new EntityGraphImpl<>(group, factory.getMetamodel()));
}
if (descriptor.hasInheritance()){
while(descriptor.getInheritancePolicy().getParentDescriptor() != null){
descriptor = descriptor.getInheritancePolicy().getParentDescriptor();
for (AttributeGroup group : descriptor.getAttributeGroups().values()){
result.add(new EntityGraphImpl<>(group));
result.add(new EntityGraphImpl<>(group, factory.getMetamodel()));
}
}
}
Expand Down

0 comments on commit 07f99f3

Please sign in to comment.