Polishing.

Simplify code flow. Introduce flag to capture whether a stored procedure uses collection return types.

Remove unconditionally the Optional converter as we're already on Java 17 and do not require the Java 8 guard.

See #2915
Original pull request: #2938
This commit is contained in:
Mark Paluch
2023-05-30 14:57:08 +02:00
parent c09c73b866
commit db28730626
3 changed files with 18 additions and 39 deletions

View File

@@ -92,7 +92,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
if (method.isStreamQuery()) {
return new StreamExecution();
} else if (method.isProcedureQuery()) {
return new ProcedureExecution();
return new ProcedureExecution(method.isCollectionQuery());
} else if (method.isCollectionQuery()) {
return new CollectionExecution();
} else if (method.isSliceQuery()) {

View File

@@ -66,7 +66,7 @@ public abstract class JpaQueryExecution {
conversionService.addConverter(JpaResultConverters.BlobToByteArrayConverter.INSTANCE);
conversionService.removeConvertible(Collection.class, Object.class);
potentiallyRemoveOptionalConverter(conversionService);
conversionService.removeConvertible(Object.class, Optional.class);
CONVERSION_SERVICE = conversionService;
}
@@ -167,7 +167,7 @@ public abstract class JpaQueryExecution {
@Override
@SuppressWarnings("unchecked")
protected Object doExecute(final AbstractJpaQuery repositoryQuery, JpaParametersParameterAccessor accessor) {
protected Object doExecute(AbstractJpaQuery repositoryQuery, JpaParametersParameterAccessor accessor) {
Query query = repositoryQuery.createQuery(accessor);
@@ -294,20 +294,25 @@ public abstract class JpaQueryExecution {
*/
static class ProcedureExecution extends JpaQueryExecution {
private final boolean collectionQuery;
private static final String NO_SURROUNDING_TRANSACTION = "You're trying to execute a @Procedure method without a surrounding transaction that keeps the connection open so that the ResultSet can actually be consumed; Make sure the consumer code uses @Transactional or any other way of declaring a (read-only) transaction";
ProcedureExecution(boolean collectionQuery) {
this.collectionQuery = collectionQuery;
}
@Override
protected Object doExecute(AbstractJpaQuery jpaQuery, JpaParametersParameterAccessor accessor) {
Assert.isInstanceOf(StoredProcedureJpaQuery.class, jpaQuery);
StoredProcedureJpaQuery storedProcedureJpaQuery = (StoredProcedureJpaQuery) jpaQuery;
StoredProcedureQuery storedProcedure = storedProcedureJpaQuery.createQuery(accessor);
StoredProcedureJpaQuery query = (StoredProcedureJpaQuery) jpaQuery;
StoredProcedureQuery procedure = query.createQuery(accessor);
try {
boolean returnsResultSet = storedProcedure.execute();
boolean returnsResultSet = procedure.execute();
if (returnsResultSet) {
@@ -315,20 +320,15 @@ public abstract class JpaQueryExecution {
throw new InvalidDataAccessApiUsageException(NO_SURROUNDING_TRANSACTION);
}
if (storedProcedureJpaQuery.getQueryMethod().isCollectionQuery()) {
return storedProcedure.getResultList();
} else {
return storedProcedure.getSingleResult();
}
return collectionQuery ? procedure.getResultList() : procedure.getSingleResult();
}
return storedProcedureJpaQuery.extractOutputValue(storedProcedure);
return query.extractOutputValue(procedure);
} finally {
if (storedProcedure instanceof AutoCloseable autoCloseable) {
if (procedure instanceof AutoCloseable ac) {
try {
autoCloseable.close();
ac.close();
} catch (Exception ignored) {}
}
}
@@ -345,10 +345,10 @@ public abstract class JpaQueryExecution {
private static final String NO_SURROUNDING_TRANSACTION = "You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed; Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction";
private static Method streamMethod = ReflectionUtils.findMethod(Query.class, "getResultStream");
private static final Method streamMethod = ReflectionUtils.findMethod(Query.class, "getResultStream");
@Override
protected Object doExecute(final AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
if (!SurroundingTransactionDetectorMethodInterceptor.INSTANCE.isSurroundingTransactionActive()) {
throw new InvalidDataAccessApiUsageException(NO_SURROUNDING_TRANSACTION);
@@ -369,24 +369,4 @@ public abstract class JpaQueryExecution {
}
}
/**
* Removes the converter being able to convert any object into an {@link Optional} from the given
* {@link ConversionService} in case we're running on Java 8.
*
* @param conversionService must not be {@literal null}.
*/
public static void potentiallyRemoveOptionalConverter(ConfigurableConversionService conversionService) {
ClassLoader classLoader = JpaQueryExecution.class.getClassLoader();
if (ClassUtils.isPresent("java.util.Optional", classLoader)) {
try {
Class<?> optionalType = ClassUtils.forName("java.util.Optional", classLoader);
conversionService.removeConvertible(Object.class, optionalType);
} catch (ClassNotFoundException | LinkageError o_O) {}
}
}
}

View File

@@ -59,7 +59,6 @@ class JpaRepositoryTests {
@BeforeEach
void setUp() {
repository = new JpaRepositoryFactory(em).getRepository(SampleEntityRepository.class);
idClassRepository = new JpaRepositoryFactory(em).getRepository(SampleWithIdClassRepository.class);
}