Closed
Description
I would like to write my own QueryDslExecutor to return a Slice instead of a Page e.g. Slice readAll. However, the QueryDslExecutor is hard coded in the factory.
@Override
protected RepositoryComposition.RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
RepositoryComposition.RepositoryFragments fragments = RepositoryComposition.RepositoryFragments.empty();
boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface());
if (isQueryDslRepository) {
if (metadata.isReactiveRepository()) {
throw new InvalidDataAccessApiUsageException(
"Cannot combine Querydsl and reactive repository support in a single interface");
}
JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
Object querydslFragment = getTargetRepositoryViaReflection(QuerydslJpaPredicateExecutor.class, entityInformation,
entityManager, entityPathResolver, crudMethodMetadataPostProcessor.getCrudMethodMetadata());
fragments = fragments.append(RepositoryFragment.implemented(querydslFragment));
}
return fragments;
}
In addition, there is no way to override the getTargetRepositoryViaReflection.
protected final <R> R getTargetRepositoryViaReflection(Class<?> baseClass, Object... constructorArguments) {
Optional<Constructor<?>> constructor = ReflectionUtils.findConstructor(baseClass, constructorArguments);
return constructor.map(it -> (R) BeanUtils.instantiateClass(it, constructorArguments))
.orElseThrow(() -> new IllegalStateException(String.format(
"No suitable constructor found on %s to match the given arguments: %s. Make sure you implement a constructor taking these",
baseClass, Arrays.stream(constructorArguments).map(Object::getClass).collect(Collectors.toList()))));
}
No member variable has a getter, so you have to rely entirely on reflection.
The (ugly) workaround looks like this
@Override
protected RepositoryComposition.RepositoryFragments getRepositoryFragments( final RepositoryMetadata metadata ) {
RepositoryComposition.RepositoryFragments fragments = RepositoryComposition.RepositoryFragments.empty();
final boolean isQueryDslRepository = QUERY_DSL_PRESENT
&& QuerydslPredicateExecutor.class.isAssignableFrom( metadata.getRepositoryInterface() );
if ( isQueryDslRepository ) {
if ( metadata.isReactiveRepository() ) {
throw new InvalidDataAccessApiUsageException(
"Cannot combine Querydsl and reactive repository support in a single interface" );
}
final JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(
metadata.getDomainType() );
final Field entityManagerField = ReflectionUtils.findField( getClass(), "entityManager" );
final Field entityPathResolverField = ReflectionUtils.findField( getClass(), "entityPathResolver" );
final Field crudMethodMetadataPostProcessorField = ReflectionUtils
.findField( getClass(), "crudMethodMetadataPostProcessor" );
final EntityManager entityManager = (EntityManager) ReflectionUtils.getField( entityManagerField, this );
final EntityPathResolver entityPathResolver = (EntityPathResolver) ReflectionUtils
.getField( entityPathResolverField, this );
final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor = (CrudMethodMetadataPostProcessor) ReflectionUtils
.getField( crudMethodMetadataPostProcessorField, this );
final Object querydslFragment = getTargetRepositoryViaReflection( MySliceableRepositoryImpl.class,
entityInformation,
entityManager, entityPathResolver, crudMethodMetadataPostProcessor.getCrudMethodMetadata() );
fragments = fragments.append( RepositoryFragment.implemented( querydslFragment ) );
}
return fragments;
}
There should be an easier way to provide a custom executor.