Skip to content
Open
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
Expand Up @@ -79,6 +79,7 @@ public class Compatibility {
private boolean _returnNullOnEmptyAggregateResult = true; // OPENJPA-1794
private boolean _cacheNonDefaultFetchPlanQueries = false; // OPENJPA-2414
private boolean _specCompliantSchemaGeneration = false; // OPENJPA-2940
private boolean _allowNestedCompoundSelection = false; // OPENJPA-2991

/**
* Whether to require exact identity value types when creating object
Expand Down Expand Up @@ -800,4 +801,27 @@ public boolean getSpecCompliantSchemaGeneration() {
public void setSpecCompliantSchemaGeneration(boolean b) {
_specCompliantSchemaGeneration = b;
}

/**
* Whether <code>CriteriaBuilder.tuple()</code> and <code>CriteriaBuilder.array()</code>
* accept compound selections as arguments. The specification forbids nesting a compound
* selection in another one, which OpenJPA rejects with an
* <code>IllegalArgumentException</code> by default. Set to true to restore the historic
* OpenJPA extension that allowed arbitrarily nested tuple and array selections.
*
* @since 4.2.0
*/
public boolean getAllowNestedCompoundSelection() {
return _allowNestedCompoundSelection;
}

/**
* Whether <code>CriteriaBuilder.tuple()</code> and <code>CriteriaBuilder.array()</code>
* accept compound selections as arguments.
*
* @since 4.2.0
*/
public void setAllowNestedCompoundSelection(boolean b) {
_allowNestedCompoundSelection = b;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.Root;

import org.apache.openjpa.conf.Compatibility;
import org.apache.openjpa.persistence.criteria.CriteriaTest;
import org.apache.openjpa.persistence.criteria.Person;
import org.apache.openjpa.persistence.criteria.Person_;
Expand Down Expand Up @@ -371,6 +372,39 @@ public void testDeeplyNestedShape() {
}
}

/**
* With the compatibility option <code>AllowNestedCompoundSelection</code> enabled,
* OpenJPA's historic extension supporting arbitrarily nested tuple and array selections
* is available again.
*/
public void testDeeplyNestedShapeWithCompatibilityOption() {
Compatibility compat = emf.getConfiguration().getCompatibilityInstance();
boolean allowed = compat.getAllowNestedCompoundSelection();
compat.setAllowNestedCompoundSelection(true);
try {
CriteriaQuery<Tuple> q = cb.createQuery(Tuple.class);
Root<Foo> foo = q.from(Foo.class);
q.multiselect(cb.construct(Foo.class, foo.get(Foo_.flong), foo.get(Foo_.fstring)),
cb.tuple(foo, cb.array(foo.get(Foo_.fint), cb.tuple(foo.get(Foo_.fstring)))));
List<Tuple> result = em.createQuery(q).getResultList();
assertFalse(result.isEmpty());
Tuple tuple = result.get(0);

assertEquals(Foo.class, tuple.get(0).getClass());
assertTrue(Tuple.class.isAssignableFrom(tuple.get(1).getClass()));
Tuple tuple2 = (Tuple)tuple.get(1);
assertEquals(Foo.class, tuple2.get(0).getClass());
assertEquals(Object[].class, tuple2.get(1).getClass());
Object[] level3 = (Object[])tuple2.get(1);
assertEquals(Integer.class, level3[0].getClass());
assertTrue(Tuple.class.isAssignableFrom(level3[1].getClass()));
Tuple tuple4 = (Tuple)level3[1];
assertEquals(String.class, tuple4.get(0).getClass());
} finally {
compat.setAllowNestedCompoundSelection(allowed);
}
}

public void testConstructorFailsFast() {
CriteriaQuery<Tuple> q = cb.createQuery(Tuple.class);
Root<Foo> foo = q.from(Foo.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import jakarta.persistence.metamodel.ManagedType;
import jakarta.persistence.metamodel.Metamodel;

import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.kernel.ExpressionStoreQuery;
import org.apache.openjpa.kernel.exps.DateTimeExtractField;
import org.apache.openjpa.kernel.exps.ExpressionFactory;
Expand Down Expand Up @@ -1113,7 +1114,7 @@

@Override
public <T> Predicate qbe(From<?, T> from, T example, ComparisonStyle style) {
return qbe(from, example, style, null);

Check warning on line 1117 in openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java

View workflow job for this annotation

GitHub Actions / build (Java 17, test-derby)

non-varargs call of varargs method with inexact argument type for last parameter;

Check warning on line 1117 in openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java

View workflow job for this annotation

GitHub Actions / build (Java 21, test-derby)

non-varargs call of varargs method with inexact argument type for last parameter;

Check warning on line 1117 in openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java

View workflow job for this annotation

GitHub Actions / build (Java 17, test-h2)

non-varargs call of varargs method with inexact argument type for last parameter;

Check warning on line 1117 in openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java

View workflow job for this annotation

GitHub Actions / build (Java 21, test-h2)

non-varargs call of varargs method with inexact argument type for last parameter;
}

@Override
Expand Down Expand Up @@ -1295,9 +1296,14 @@

/**
* Validates that none of the given selections is a compound (tuple or array) selection.
* Per JPA spec, tuple() and array() must not accept compound selection arguments.
* Per JPA spec, tuple() and array() must not accept compound selection arguments. The
* compatibility option <code>AllowNestedCompoundSelection</code> restores the historic
* OpenJPA extension that allowed arbitrarily nested tuple and array selections.
*/
private void assertNoCompoundSelections(Selection<?>... selections) {
if (isNestedCompoundSelectionAllowed()) {
return;
}
for (Selection<?> s : selections) {
if (s.isCompoundSelection()) {
throw new IllegalArgumentException(
Expand All @@ -1306,4 +1312,13 @@
}
}

private boolean isNestedCompoundSelectionAllowed() {
if (_model == null) {
return false;
}
OpenJPAConfiguration conf = _model.getConfiguration();
return conf != null && conf.getCompatibilityInstance() != null
&& conf.getCompatibilityInstance().getAllowNestedCompoundSelection();
}

}
7 changes: 7 additions & 0 deletions openjpa-project/src/doc/manual/migration_considerations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,13 @@
subclasses. Flatten nested selections, use unique aliases and adjust catch blocks
and <literal>null</literal> checks accordingly.
</para>
<para>
Rejecting nested compound selections removes a documented OpenJPA extension
that supported arbitrarily nested tuple and array selections. Applications
relying on it can restore the previous behavior with the compatibility option
<literal>AllowNestedCompoundSelection</literal>:
</para>
<programlisting>&lt;property name="openjpa.Compatibility" value="AllowNestedCompoundSelection=true"/&gt;</programlisting>
</section>
<section id="jpa_4.2_PersistenceUnitUtilIdentifier">
<title>PersistenceUnitUtil.getIdentifier() returns the plain identifier</title>
Expand Down
Loading