Skip to content

Introduce template method for easier customization of fragments #2202

@MelleD

Description

@MelleD

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.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions