Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jakarta Persistence 3.2: #1996

Merged
merged 6 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2022 IBM Corporation.
* Copyright (c) 2010, 2022 Dies Koper (Fujitsu).
*
Expand Down Expand Up @@ -187,7 +187,7 @@ protected static FieldDefinition createNumericPk(
field.setSize(size);
field.setShouldAllowNull(false);
field.setIsPrimaryKey(true);
field.setUnique(true);
field.setUnique(false);
field.setIsIdentity(true);
return field;
}
Expand All @@ -205,18 +205,19 @@ protected static FieldDefinition createNumericPk(final String name) {
/**
* Helper method to create {@link FieldDefinition} instance for
* numeric foreign key with given name, size and foreign key name.
* @param name Column name.
* @param size Column numeric type size.
* @param name Column name.
* @param size Column numeric type size.
* @param fkName Foreign key name (e.g. {@code "MY_TABLE.ID"}.
* @param allowNull Allow {@code null} values for column.
* @return Initialized {@link FieldDefinition} instance.
*/
protected static FieldDefinition createNumericFk(
final String name, final int size, final String fkName) {
final String name, final int size, final String fkName, final boolean allowNull) {
final FieldDefinition field = new FieldDefinition();
field.setName(name);
field.setTypeName("NUMERIC");
field.setSize(size);
field.setShouldAllowNull(false);
field.setShouldAllowNull(allowNull);
field.setIsPrimaryKey(false);
field.setUnique(false);
field.setIsIdentity(false);
Expand All @@ -229,11 +230,12 @@ protected static FieldDefinition createNumericFk(
* numeric foreign key with given name, foreign key name and default size
* of {@code 15}.
* @param name Column name.
* @param fkName Foreign key name (e.g. {@code "MY_TABLE.ID"}.
* @return Initialized {@link FieldDefinition} instance.
*/
protected static FieldDefinition createNumericFk(
final String name, final String fkName) {
return createNumericFk(name, 15, fkName);
return createNumericFk(name, 15, fkName, false);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,13 @@ protected Expression prepareJoinExpression(Expression expression, AbstractSessio
}
objectExpression.getBuilder().setSession(session.getRootSession(null));

// Sometimes current expression builder does not support expression class mapping.
// Try ExpressionBuilder for the descriptor's class
if (objectExpression.getMapping() == null && objectExpression.getBuilder().getQueryClass() != descriptor.getJavaClass()) {
objectExpression = (QueryKeyExpression)objectExpression.rebuildOn(new ExpressionBuilder(descriptor.getJavaClass()));
objectExpression.getBuilder().setSession(session.getRootSession(null));
}

// Can only join relationships.
if ((objectExpression.getMapping() == null) || (!objectExpression.getMapping().isJoiningSupported())) {
throw QueryException.mappingForExpressionDoesNotSupportJoining(objectExpression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ public void addAttribute(String attributeNameOrPath, AttributeGroup group) {
super.addAttribute(attributeNameOrPath, group);
}

/**
* Remove an attribute from the group.
* @param attributeNameOrPath a simple attribute, array or attributes forming a path
*/
public void removeAttribute(String attributeNameOrPath) {
super.removeAttribute(attributeNameOrPath);
}

/**
* Returns AttributeGroup corresponding to the passed (possibly nested)
* attribute.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
// 09/21/2010-2.2 Frank Schwarz and ailitchev - Bug 325684 - QueryHints.BATCH combined with QueryHints.FETCH_GROUP_LOAD will cause NPE
// 3/13/2015 - Will Dazey
// - 458301 : Added check so that aggregate results won't attempt force version lock if locking type is set
// 10/25/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.queries;

import org.eclipse.persistence.annotations.BatchFetchType;
Expand Down Expand Up @@ -263,6 +265,16 @@ protected ObjectLevelReadQuery() {
*/
public void union(ReportQuery query) {
addUnionExpression(getExpressionBuilder().union(query));
copyQueryArguments(query);
}

/**
* PUBLIC:
* UnionAll the query results with the other query.
*/
public void unionAll(ReportQuery query) {
addUnionExpression(getExpressionBuilder().unionAll(query));
copyQueryArguments(query);
}

/**
Expand All @@ -271,6 +283,16 @@ public void union(ReportQuery query) {
*/
public void intersect(ReportQuery query) {
addUnionExpression(getExpressionBuilder().intersect(query));
copyQueryArguments(query);
}

/**
* PUBLIC:
* IntersectAll the query results with the other query.
*/
public void intersectAll(ReportQuery query) {
addUnionExpression(getExpressionBuilder().intersectAll(query));
copyQueryArguments(query);
}

/**
Expand All @@ -279,6 +301,44 @@ public void intersect(ReportQuery query) {
*/
public void except(ReportQuery query) {
addUnionExpression(getExpressionBuilder().except(query));
copyQueryArguments(query);
}

/**
* PUBLIC:
* ExceptAll the query results with the other query.
*/
public void exceptAll(ReportQuery query) {
addUnionExpression(getExpressionBuilder().exceptAll(query));
copyQueryArguments(query);
}

// Union/intersect/except methods helper
// Copy arguments, argumentTypes, argumentTypeNames and nullableArguments
private void copyQueryArguments(ReportQuery query) {
List<String> arguments = query.arguments;
List<Class<?>> argumentTypes = query.argumentTypes;
// Arguments and argumentTypes Lists shall have the same size
int size = arguments != null ? arguments.size() : 0;
for (int i = 0; i < size; i++) {
String argument = arguments.get(i);
// Mark as non-nullable to avoid unnecessary DatabaseField clone
addArgument(argument, argumentTypes.get(i));
// Copy nullable information for current argument if exists
if (query.nullableArguments != null) {
List <DatabaseField> nullableArguments = query.nullableArguments;
DatabaseField nullable = null;
for (DatabaseField nullableArgument : nullableArguments) {
if (nullableArgument.getQualifiedName().equals(argument)) {
nullable = nullableArgument;
break;
}
}
if (nullable != null) {
this.getNullableArguments().add(nullable);
}
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,15 +769,15 @@ public Object clone() {
* Each call to copiedVersionFrom() will take O(1) time as the expression was
* already cloned.
*/
public void copyReportItems(Map alreadyDone) {
public void copyReportItems(Map<Expression, Expression> alreadyDone) {
this.items = new ArrayList<>(this.items);
for (int i = this.items.size() - 1; i >= 0; i--) {
ReportItem item = this.items.get(i);
Expression expression = item.getAttributeExpression();
if ((expression != null) && (alreadyDone.get(expression.getBuilder()) != null)) {
expression = expression.copiedVersionFrom(alreadyDone);
if (item.isConstructorItem()) {
this.items.set(i, copyConstructorReportItem((ConstructorReportItem) item, alreadyDone));
} else {
this.items.set(i, copyReportItem(item, alreadyDone));
}
this.items.set(i, new ReportItem(item.getName(), expression));
}
if (this.groupByExpressions != null) {
this.groupByExpressions = new ArrayList<>(this.groupByExpressions);
Expand All @@ -801,6 +801,39 @@ public void copyReportItems(Map alreadyDone) {
}
}

// copyReportItems helper
private static ConstructorReportItem copyConstructorReportItem(ConstructorReportItem reportItem, Map<Expression, Expression> alreadyDone) {
// Copy ReportItems list if exists
List<ReportItem> reportItems = reportItem.getReportItems();
List<ReportItem> newReportItems = reportItems != null ? new ArrayList<>(reportItems.size()) : null;
if (reportItems != null) {
for (ReportItem item : reportItems) {
newReportItems.add(copyReportItem(item, alreadyDone));
}
}
// Create new ConstructorReportItem
ConstructorReportItem newItem = new ConstructorReportItem(reportItem.getName());
newItem.setConstructor(reportItem.getConstructor());
newItem.setResultType(reportItem.getResultType());
newItem.setReportItems(newReportItems);
newItem.setAttributeExpression(copyAttributeExpression(reportItem, alreadyDone));
return newItem;
}

// copyReportItems helper
private static Expression copyAttributeExpression(ReportItem reportItem, Map<Expression, Expression> alreadyDone) {
Expression expression = reportItem.getAttributeExpression();
if ((expression != null) && (alreadyDone.get(expression.getBuilder()) != null)) {
expression = expression.copiedVersionFrom(alreadyDone);
}
return expression;
}

// copyReportItems helper
private static ReportItem copyReportItem(ReportItem reportItem, Map<Expression, Expression> alreadyDone) {
return new ReportItem(reportItem.getName(), copyAttributeExpression(reportItem, alreadyDone));
}

/**
* PUBLIC:
* Set if the query results should contain the primary keys or each associated object.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
Expand Down Expand Up @@ -27,6 +27,7 @@
import jakarta.persistence.Query;
import jakarta.persistence.Tuple;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CompoundSelection;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaBuilder.Case;
import jakarta.persistence.criteria.CriteriaBuilder.Coalesce;
Expand Down Expand Up @@ -3008,7 +3009,7 @@ public void testCriteriaBuilderTupleValidation() {
CriteriaQuery<Tuple> cquery = qb.createTupleQuery();

Root<Employee> emp = wrapper.from(cquery, Employee.class);
Selection[] s = {wrapper.get(emp, Employee_id), wrapper.get(emp, Employee_lastName), wrapper.get(emp, Employee_firstName)};
Selection<?>[] s = {wrapper.get(emp, Employee_id), wrapper.get(emp, Employee_lastName), wrapper.get(emp, Employee_firstName)};
Selection<Tuple> item = qb.tuple(s);
cquery.select(item);

Expand All @@ -3018,16 +3019,56 @@ public void testCriteriaBuilderTupleValidation() {
list.get(0);
try {
//verify tuple throws an exception when passed a tuple
Object unexpectedResult = qb.tuple(item);
fail("IllegalArgumentException expected using an invalid value to CriteriaBuilder.tuple(). Result returned:"+unexpectedResult);
CompoundSelection<Tuple> unexpectedResult = qb.tuple(item);
fail("IllegalArgumentException expected using an invalid value to CriteriaBuilder.tuple(). Result returned:"
+ unexpectedResult.toString());
} catch (Exception iae) {
assertEquals(iae.getClass(), IllegalArgumentException.class);
}

try {
//verify array throws an exception when passed a tuple
Object unexpectedResult = qb.array(item);
fail("IllegalArgumentException expected using an invalid value to CriteriaBuilder.array(). Result returned:"+unexpectedResult);
CompoundSelection<Object[]> unexpectedResult = qb.array(item);
fail("IllegalArgumentException expected using an invalid value to CriteriaBuilder.array(). Result returned:"
+ unexpectedResult.toString());
} catch (Exception iae) {
assertEquals(iae.getClass(), IllegalArgumentException.class);
}
closeEntityManager(em);
}

// Verify that CriteriaBuilder.tuple(List<Selection>) does not throw IllegalArgumentException
public void testCriteriaBuilderTupleOfListValidation() {
EntityManager em = createEntityManager();

CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cquery = qb.createTupleQuery();

Root<Employee> emp = wrapper.from(cquery, Employee.class);
List<Selection<?>> s = List.of(wrapper.get(emp, Employee_id),
wrapper.get(emp, Employee_lastName),
wrapper.get(emp, Employee_firstName));
Selection<Tuple> item = qb.tuple(s);
cquery.select(item);

TypedQuery<Tuple> query = em.createQuery(cquery);
//verify they work and can be used:
List<Tuple> list = query.getResultList();
list.get(0);
try {
//verify tuple throws an exception when passed a tuple
CompoundSelection<Tuple> unexpectedResult = qb.tuple(List.of(item));
fail("IllegalArgumentException expected using an invalid value to CriteriaBuilder.tuple(). Result returned:"
+ unexpectedResult.toString());
} catch (Exception iae) {
assertEquals(iae.getClass(), IllegalArgumentException.class);
}

try {
//verify array throws an exception when passed a tuple
CompoundSelection<Object[]> unexpectedResult = qb.array(item);
fail("IllegalArgumentException expected using an invalid value to CriteriaBuilder.array(). Result returned:"
+ unexpectedResult.toString());
} catch (Exception iae) {
assertEquals(iae.getClass(), IllegalArgumentException.class);
}
Expand Down
15 changes: 15 additions & 0 deletions jpa/eclipselink.jpa.testapps/jpa.test.persistence32/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@
</execution>
</executions>
</plugin>
<!-- Static metamodel is used in tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>compile-with-processor</id>
<phase>compile</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

package org.eclipse.persistence.testing.models.jpa.persistence32;

import org.eclipse.persistence.testing.framework.TogglingFastTableCreator;
Expand All @@ -19,12 +18,31 @@ public class Persistence32TableCreator extends TogglingFastTableCreator {

public Persistence32TableCreator() {
setName("Persistence32Project");
addTableDefinition(buildTeamTable());
addTableDefinition(buildTrainerTable());
addTableDefinition(buildTypeTable());
addTableDefinition(buildPokemonTable());
addTableDefinition(buildPokemonTypeTable());
addTableDefinition(buildSyntaxEntityTable());
}

public static TableDefinition buildTeamTable() {
TableDefinition table = new TableDefinition();
table.setName("PERSISTENCE32_TEAM");
table.addField(createNumericPk("ID"));
table.addField(createStringColumn("NAME", 64, false));
return table;
}

public static TableDefinition buildTrainerTable() {
TableDefinition table = new TableDefinition();
table.setName("PERSISTENCE32_TRAINER");
table.addField(createNumericPk("ID"));
table.addField(createStringColumn("NAME", 64, false));
table.addField(createNumericFk("TEAM_ID", 15,"PERSISTENCE32_TEAM.ID", false));
return table;
}

public static TableDefinition buildTypeTable() {
TableDefinition table = new TableDefinition();
table.setName("PERSISTENCE32_TYPE");
Expand All @@ -37,6 +55,7 @@ public static TableDefinition buildPokemonTable() {
TableDefinition table = new TableDefinition();
table.setName("PERSISTENCE32_POKEMON");
table.addField(createNumericPk("ID"));
table.addField(createNumericFk("TRAINER_ID", 15,"PERSISTENCE32_TRAINER.ID", true));
table.addField(createStringColumn("NAME", 64, false));
return table;
}
Expand Down
Loading
Loading