Skip to content

Commit

Permalink
Migration to Java 21 (#31)
Browse files Browse the repository at this point in the history
* Updated project to Java 21, migrated to Jakarta namespace and updated dependencies to latest version.

* Randomly generate UUID and assign it to project entity in test DB init

* Set org.ow2.asm (parboiled-java dependency) version to latest to support Java 21

* Fix UUID converter used to convert database/entity UUID attribute

* Update key to 'jakarta' package

* Fix Timestamp DB type filtering in JPAUtils

* Fix UUID type filtering in StreamUtils

* Fix tests to compensate for SQL schema UUID generation for Project entities publicId field

* Add fix and tests for ISNULL and ISNOTNULL filter operation over non-associated collections

* Run stream tests between transaction

* Set source version to 11

* added java 21 to runner

---------

Co-authored-by: davidtrafela <[email protected]>
Co-authored-by: Benjamin Kastelic <[email protected]>
  • Loading branch information
3 people authored Mar 15, 2024
1 parent 54bb123 commit 4f1a50b
Show file tree
Hide file tree
Showing 35 changed files with 338 additions and 219 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/kumuluzee-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:

strategy:
matrix:
java-version: ['11', '17']
java-version: ['11', '17', '21']

steps:
- name: Checkout code
Expand Down Expand Up @@ -67,4 +67,4 @@ jobs:
OSSRH_USERNAME: Kumuluz
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_PASSPHRASE }}
run: mvn --batch-mode source:jar javadoc:jar deploy -Pdeploy -DskipTests=true --settings ./settings.xml;
run: mvn --batch-mode source:jar javadoc:jar deploy -Pdeploy -DskipTests=true --settings ./settings.xml;
6 changes: 3 additions & 3 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<artifactId>kumuluzee-rest</artifactId>
<groupId>com.kumuluz.ee.rest</groupId>
<version>2.1.0-SNAPSHOT</version>
<version>3.0.0-SNAPSHOT</version>
</parent>

<name>KumuluzEE REST Core</name>
Expand All @@ -17,8 +17,8 @@

<dependencies>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency>
<groupId>org.parboiled</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
*/
package com.kumuluz.ee.rest.beans;

import javax.persistence.criteria.Path;
import jakarta.persistence.criteria.Path;

import java.io.Serializable;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
*/
package com.kumuluz.ee.rest.beans;

import javax.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Predicate;

import java.io.Serializable;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public void setFields(List<String> fields) {
* {@link #addFilterExpression(FilterExpressionOperation, QueryFilterExpression)} ()} instead.
*/
public void addFilter(QueryFilter filter) {
if(filter != null) {
if (filter != null) {
getFilters().add(filter);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
*/
package com.kumuluz.ee.rest.interfaces;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;

/**
* @author Tilen Faganel
Expand Down
71 changes: 44 additions & 27 deletions core/src/main/java/com/kumuluz/ee/rest/utils/JPAUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,18 @@
import com.kumuluz.ee.rest.exceptions.NoSuchEntityFieldException;
import com.kumuluz.ee.rest.exceptions.QueryFormatException;
import com.kumuluz.ee.rest.interfaces.CriteriaFilter;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Tuple;
import jakarta.persistence.TupleElement;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.*;
import jakarta.persistence.metamodel.*;

import javax.persistence.EntityManager;
import javax.persistence.Tuple;
import javax.persistence.TupleElement;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import javax.persistence.metamodel.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeParseException;
import java.util.*;
Expand All @@ -57,7 +58,7 @@ public class JPAUtils {

private static final Logger LOG = Logger.getLogger(JPAUtils.class.getSimpleName());

private static final String PROP_PERSISTENCE_JDBC_DRIVER = "javax.persistence.jdbc.driver";
private static final String PROP_PERSISTENCE_JDBC_DRIVER = "jakarta.persistence.jdbc.driver";
private static final String POSTGRES_SQL_DRIVER = "org.postgresql.Driver";

public static <T> Stream<T> getEntityStream(EntityManager em, Class<T> entity) {
Expand Down Expand Up @@ -194,7 +195,7 @@ public static <T> List<T> queryEntities(EntityManager em, Class<T> entity, Query
}

private static <T> Optional<TypedQuery<T>> buildQuery(EntityManager em, Class<T> entity, QueryParameters q, CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias, boolean forceDistinct) {
List<QueryHintPair> queryHints, String rootAlias, boolean forceDistinct) {
if (em == null || entity == null)
throw new IllegalArgumentException("The entity manager and the entity cannot be null.");

Expand Down Expand Up @@ -384,17 +385,17 @@ public static List<Selection<?>> createFieldsSelect(Root<?> r, QueryParameters q
// Temporary methods to not break the public API

private static <T> Optional<TypedQuery<T>> buildQuerySimple(EntityManager em, Class<T> entity, QueryParameters q,
CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias,
boolean forceDistinct) {
CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias,
boolean forceDistinct) {
return buildQuerySimple(em, entity, q, customFilter, queryHints, rootAlias, forceDistinct, false);
}

@SuppressWarnings("unchecked")
private static <T> Optional<TypedQuery<T>> buildQuerySimple(EntityManager em, Class<T> entity, QueryParameters q,
CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias,
boolean forceDistinct, boolean ignorePaging) {
CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias,
boolean forceDistinct, boolean ignorePaging) {

LOG.finest("Querying entity: '" + entity.getSimpleName() + "' with parameters: " + q + "(simple)");

Expand Down Expand Up @@ -478,9 +479,9 @@ private static <T> Optional<TypedQuery<T>> buildQuerySimple(EntityManager em, Cl

@SuppressWarnings("unchecked")
private static <T> Optional<TypedQuery<T>> buildQueryAdvanced(EntityManager em, Class<T> entity, QueryParameters q,
CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias,
boolean forceDistinct) {
CriteriaFilter<T> customFilter,
List<QueryHintPair> queryHints, String rootAlias,
boolean forceDistinct) {

LOG.finest("Querying entity: '" + entity.getSimpleName() + "' with parameters: " + q + "(advanced)");

Expand Down Expand Up @@ -580,6 +581,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
Attribute attribute = (Attribute) entityField.getModel();

boolean isBasic = attribute.getPersistentAttributeType().equals(Attribute.PersistentAttributeType.BASIC);
boolean isAssociation = attribute.isAssociation();
boolean isCollection = attribute.isCollection();

@SuppressWarnings("unchecked")
Expand All @@ -594,7 +596,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
switch (f.getOperation()) {

case EQ:
if (f.getDateValue() != null && entityField.getJavaType().equals(Date.class)) {
if (f.getDateValue() != null && Date.class.isAssignableFrom(entityField.getJavaType())) {
np = cb.equal(entityField, f.getDateValue());
} else if (f.getValue() != null) {
np = cb.equal(entityField, getValueForPath(entityField, f.getValue()));
Expand All @@ -606,7 +608,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
}
break;
case NEQ:
if (f.getDateValue() != null && entityField.getJavaType().equals(Date.class)) {
if (f.getDateValue() != null && Date.class.isAssignableFrom(entityField.getJavaType())) {
np = cb.notEqual(entityField, f.getDateValue());
} else if (f.getValue() != null) {
np = cb.notEqual(entityField, getValueForPath(entityField, f.getValue()));
Expand Down Expand Up @@ -671,7 +673,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
Number.class.isAssignableFrom(entityField.getJavaType()) ||
String.class.isAssignableFrom(entityField.getJavaType())) {

if (f.getDateValue() != null && entityField.getJavaType().equals(Date.class)) {
if (f.getDateValue() != null && Date.class.isAssignableFrom(entityField.getJavaType())) {
np = cb.greaterThan(dateField, f.getDateValue());
} else if (f.getValue() != null) {
np = cb.greaterThan(compField, (Comparable) getValueForPath(stringField, f.getValue()));
Expand All @@ -684,7 +686,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
Number.class.isAssignableFrom(entityField.getJavaType()) ||
String.class.isAssignableFrom(entityField.getJavaType())) {

if (f.getDateValue() != null && entityField.getJavaType().equals(Date.class)) {
if (f.getDateValue() != null && Date.class.isAssignableFrom(entityField.getJavaType())) {
np = cb.greaterThanOrEqualTo(dateField, f.getDateValue());
} else if (f.getValue() != null) {
np = cb.greaterThanOrEqualTo(compField, (Comparable) getValueForPath(stringField, f.getValue()));
Expand All @@ -697,7 +699,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
Number.class.isAssignableFrom(entityField.getJavaType()) ||
String.class.isAssignableFrom(entityField.getJavaType())) {

if (f.getDateValue() != null && entityField.getJavaType().equals(Date.class)) {
if (f.getDateValue() != null && Date.class.isAssignableFrom(entityField.getJavaType())) {
np = cb.lessThan(dateField, f.getDateValue());
} else if (f.getValue() != null) {
np = cb.lessThan(compField, (Comparable) getValueForPath(stringField, f.getValue()));
Expand All @@ -710,7 +712,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
Number.class.isAssignableFrom(entityField.getJavaType()) ||
String.class.isAssignableFrom(entityField.getJavaType())) {

if (f.getDateValue() != null && entityField.getJavaType().equals(Date.class)) {
if (f.getDateValue() != null && Date.class.isAssignableFrom(entityField.getJavaType())) {
np = cb.lessThanOrEqualTo(dateField, f.getDateValue());
} else if (f.getValue() != null) {
np = cb.lessThanOrEqualTo(compField, (Comparable) getValueForPath(stringField, f.getValue()));
Expand Down Expand Up @@ -778,7 +780,7 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
);
}
}
} else if (isCollection) {
} else if (isAssociation) {

String idField;

Expand All @@ -792,6 +794,16 @@ private static Predicate createWhereQueryInternal(EntityManager em, CriteriaBuil
np = cb.isNotNull(entityField.get(idField));
break;
}
} else if (isCollection) {

switch (f.getOperation()) {
case ISNULL:
np = cb.isEmpty(entityField);
break;
case ISNOTNULL:
np = cb.isNotEmpty(entityField);
break;
}
}
} catch (IllegalArgumentException e) {
throw new NoSuchEntityFieldException(e.getMessage(), f.getField(), r.getJavaType().getSimpleName());
Expand Down Expand Up @@ -840,7 +852,7 @@ private static <T> Stream<T> createEntitiesFromTuples(List<Tuple> tuples, Class<
try {
el = entity.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException |
NoSuchMethodException | InvocationTargetException e) {
NoSuchMethodException | InvocationTargetException e) {

throw new AssertionError();
}
Expand All @@ -864,7 +876,8 @@ private static <T> Stream<T> createEntitiesFromTuples(List<Tuple> tuples, Class<
String[] fName = te.getAlias().split("\\.");

createEntityFromTuple(fName, entity, el, o, i);
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException | InstantiationException e) {

throw new NoSuchEntityFieldException(e.getMessage(), te.getAlias(), entity.getSimpleName());
}
Expand Down Expand Up @@ -1059,6 +1072,10 @@ private static Object getValueForPath(Path path, String value) {
return Date.from(ZonedDateTime.parse(value).toInstant());
}

if (c.equals(Timestamp.class)) {
return Timestamp.from(ZonedDateTime.parse(value).toInstant());
}

if (c.equals(Instant.class)) {
return ZonedDateTime.parse(value).toInstant();
}
Expand Down Expand Up @@ -1135,7 +1152,7 @@ private static CriteriaField getCriteriaField(String fieldName, Root<?> r, Map<S
String mappedFieldName = mappedFieldOptional.get();

String[] mappedFields = mappedFieldName.split("\\.");
for (String mappedField: mappedFields) {
for (String mappedField : mappedFields) {
fieldPath = fieldPath == null ? mappedField : fieldPath + "." + mappedField;

if (fieldJoins.containsKey(fieldPath)) {
Expand Down
13 changes: 10 additions & 3 deletions core/src/main/java/com/kumuluz/ee/rest/utils/StreamUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ private static StreamCriteriaWhereQuery createWhereQueryInternal(Class<?> clazz,

private static StreamCriteriaField getStreamCriteriaField(Class<?> clazz, String fieldName) {

if (fieldName == null) throw new NoSuchEntityFieldException("No such entity field", fieldName, clazz.getSimpleName());
if (fieldName == null)
throw new NoSuchEntityFieldException("No such entity field", fieldName, clazz.getSimpleName());

String[] fields = fieldName.split("\\.");

Expand Down Expand Up @@ -589,6 +590,8 @@ private static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object
return (((Date) value).toInstant()).equals(((Date) fieldValue).toInstant());
} else if (value instanceof Enum) {
return value.equals(getValueForField(field, fieldValue.toString()));
} else if (value instanceof UUID) {
return value.equals(UUID.fromString(fieldValue.toString()));
} else if (Collection.class.isAssignableFrom(value.getClass())) {

Predicate newPredicate = filter(getGenericType(field), fieldName.substring(fieldNames[0].length() + 1),
Expand Down Expand Up @@ -651,6 +654,8 @@ private static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object
return !(((Date) value).toInstant()).equals(((Date) fieldValue).toInstant());
} else if (value instanceof Enum) {
return !value.equals(getValueForField(field, fieldValue.toString()));
} else if (value instanceof UUID) {
return !value.equals(UUID.fromString(fieldValue.toString()));
} else if (Collection.class.isAssignableFrom(value.getClass())) {

Predicate newPredicate = filter(getGenericType(field), fieldName.substring(fieldNames[0].length() + 1),
Expand Down Expand Up @@ -933,7 +938,8 @@ private static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object
} else if (operation.equals(FilterOperation.IN)) {
if (value != null) {
if (value instanceof String || value instanceof Double || value instanceof Float || value instanceof Long ||
value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Date || value instanceof Enum) {
value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Date ||
value instanceof Enum || value instanceof UUID) {

return ((List<?>) fieldValue).stream()
.filter(Objects::nonNull)
Expand Down Expand Up @@ -982,7 +988,8 @@ private static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object
} else if (operation.equals(FilterOperation.NIN)) {
if (value != null) {
if (value instanceof String || value instanceof Double || value instanceof Float || value instanceof Long ||
value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Date || value instanceof Enum) {
value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Date ||
value instanceof Enum || value instanceof UUID) {

return !((List<?>) fieldValue).stream()
.filter(Objects::nonNull)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import com.kumuluz.ee.rest.test.entities.User;
import com.kumuluz.ee.rest.test.utils.JpaUtil;
import com.kumuluz.ee.rest.utils.JPAUtils;
import jakarta.persistence.EntityManager;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import javax.persistence.EntityManager;
import java.util.Arrays;
import java.util.Collection;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import com.kumuluz.ee.rest.test.entities.User;
import com.kumuluz.ee.rest.test.utils.JpaUtil;
import com.kumuluz.ee.rest.utils.JPAUtils;
import jakarta.persistence.EntityManager;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import javax.persistence.EntityManager;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
Expand Down
Loading

0 comments on commit 4f1a50b

Please sign in to comment.