Skip to content

Introduce template method for easier customization of fragments #2202

Closed
@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