Skip to content

Custom implementation of CrudRepository.save(…) not called if generics not declared exactly [DATACMNS-1008] #1458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Mar 13, 2017 · 2 comments
Assignees
Labels
in: repository Repositories abstraction type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link

Ryon Day opened DATACMNS-1008 and commented

This issue is in conjunction with this spring-data-dynamodb issue.

I've spent a few hours on this bug and have tracked down the root cause as well as a workaround, but there appears to be no solution.

Library Versions

  • spring-data-dynamoDB version: 4.5.0
  • Spring-data-commons version: 1.13.1-RELEASE

Situation

I have a base repository interface:

interface FooRepository extends CrudRepository<Foo, Long>, FooRepositoryCustom{}

...and a custom repository interface:

interface UserRepositoryCustom {
    Foo doNonstandardThing(Foo foo);
}

... and a custom repository implementation:

class UserRepositoryImpl implements UserRepositoryCustom {
    public Foo save(Foo foo) { … }
    public Foo doNonstandardThing(Foo foo) { … }
}

... If I use this custom repository:

@Service
public class FooService {

    private final FooRepository fooRepo;
    
    @Autowired
    public FooService(FooRepository fooRepo) {
        this.fooRepo = fooRepo;
    }

    public Bar processFoo(Foo foo) {
        fooRepo.save(foo);
    }
}

With spring-data-dynamodb:4.2.3 using spring-data-commons:1.11.4-RELEASE, the fooRepo.save(…) call in FooService would call the save(…) method on FooRepositoryCustom. with spring-data-dynamodb:4.5.0 and spring-data-commons:1.13.1-RELEASE, it actually calls SimpleDynamoDBCrudRepository.save(…), which is the base implementation used by the Spring scoped proxy.

After some quality time in side-by-side debuggers with my code running on the new and old versions of the library, I've tracked the offending code change down to this commit as well as a few other changes within DefaultRepositoryInformation and specifically, the parametersMatch(…) method. The logic over whether a custom repository method "matches" seems to have changed in a very odd and restrictive way.

What I can't figure out is why exactly Spring cannot tell that a method with the exact needed signature in my custom repository is not suitable to call vs. the proxy method in the spring-data-dynamodb library.

Workaround

Changing the Custom Repository interface like so:

interface FooRepository extends CrudRepository<Foo, Long>, FooRepositoryCustom{

    @Override
    <X extends Foo> X save(X foo);
}

causes the correct method to be invoked, but this should not be necessary; it is also tedious to do for every repository that happens to have a custom implementation of a "standard" CrudRepository method.

Desired State

Methods in custom repositories should be respected by return and parameter value


Affects: 1.13.1 (Ingalls SR1), 1.12.8 (Hopper SR8)

Issue Links:

  • DATACMNS-1225 Custom implementation of CrudRepository.save() not called if generics not declared exactly (reopener)

  • DATACMNS-854 Custom implementation of repository fails when overriding methods containing generics

  • DATACMNS-912 Unable to write custom implementation of CRUD method with generic parameters

Backported to: 1.13.2 (Ingalls SR2), 1.12.9 (Hopper SR9)

@spring-projects-issues
Copy link
Author

Oliver Drotbohm commented

Thanks for the detailed analysis, Ryon. In fact, the refactoring seems to have lost the consideration of exact matches on the declared method. I have a local fix ready with that additional if clause introduced again.

In the mean time, it should be sufficient to introduce the method on the implementation class with the exact generic signature (<T extends Foo> T save(T entity)), i.e. you don't need to pull it up into the interface necessarily

@spring-projects-issues
Copy link
Author

Oliver Drotbohm commented

This is in place, feel free to give the snapshots a try

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: repository Repositories abstraction type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants