0

So I was following the tutorial here: https://spring.io/guides/gs/accessing-data-jpa/

and it works fine, I'm trying to implement it in my application (Because it makes JPA so easy to use), but I'm confused.

Where it has

 @Bean
 public CommandLineRunner demo(CustomerRepository repository)

and then it acts on the repository

repository.save(new Customer("Jack", "Bauer"));
        repository.save(new Customer("Chloe", "O'Brian")); 

How can it act on an interface? CustomerRepository is an interface, and I can't instantiate it

CustomerRepository c = new CustomerRepository() 

cant be done, and I don't have any classes that implement the interface. I just wanted to do something like

 CustomerRepository c = new CustomerRepository() 
 c.save(new Customer("whatever", "whatever")

but I can only use it in the CommandLineRunner bean method. Why can I do this with commandlinerunner but cant do it with another class?

I was thinking I could just make a class that extends CustomerRepository, but then I read that the interface actually does all the method implementation itself (JPA does it) so you don't have to worry about it.

public interface CustomerRepository extends CrudRepository<Customer, Long> {

List<Customer> findByLastName(String lastName);
}

so if I extended it, wouldn't I have to override the findbylastname() method, meaning JPA wouldn't do it itself?

Thanks for any assistance.

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
Smithers
  • 39
  • 1
  • 4

2 Answers2

0

I extended it, wouldn't I have to override the findbylastname() method, meaning JPA wouldn't do it itself ?

No, you don't need to implement the methods as spring-data-jpa will take care of it, you can look here on how Spring data repository interfaces are actually implemented by proxy at runtime.

The main point that you need to remember is that spring data has got few rules to derive the sql queries from the method names (like findByLastName(), findByLastnameOrderByFirstnameAsc(), etc..), you can look here to understand how method names work and they are related to field names of your entity bean.

If you wanted to write some complex queries which can't be derived from method names you can use @Query for your methods.

If I made a class public class Cust implements CustomerRepository what would I do when it asks me I have to implement the findByLastName(String lastName); method that JPA is supposed to take care of ?

If you wanted to implement repository to provide your custom behaviour for few of the methods for few of your methods, you can do that (like class Cust implements CustomerRepository), you can refer the section "Using JpaContext in custom implementations", it is well explained in the ref doc.

Community
  • 1
  • 1
Vasu
  • 21,832
  • 11
  • 51
  • 67
  • Thanks. So I could just use a class that implements CustomerRepository and not have to implement the method, i could just call it? – Smithers Nov 27 '16 at 07:53
  • yes, you are right, ensure that your method names are proper i.e., they should follow java bean naming conventions as shown above & in doc. – Vasu Nov 27 '16 at 07:55
  • So if I made a class public class Cust implements CustomerRepository what would I do when it asks me I have to implement the findByLastName(String lastName); method that JPA is supposed to take care of? – Smithers Nov 27 '16 at 07:58
  • Okay I'll take a loot at that, I mainly didnt want to have to screw with anything because the find methods work fine, just wanted to use the CustomerRepository outside the commandlinerunner bean. – Smithers Nov 27 '16 at 08:05
  • okay, simple queries fine work with findByX() methods, also u can use @Query – Vasu Nov 27 '16 at 08:08
0

so if I extended it, wouldn't I have to override the findbylastname() method, meaning JPA wouldn't do it itself?

No, it is not JPA which does the job but Spring which generates by APO some JPA processings.

With Spring Repository, you have multiples ways of doing :

  • write your own SQL/JPQL query.
  • use naming convention in the method name to write the query

In both cases, you don't need to implement directly the interface you declare here :

public interface CustomerRepository extends CrudRepository<Customer, Long> {   
   List<Customer> findByLastName(String lastName);
}

Because as you understood, the job is performed for you by Spring.
For example, in the case you quote, you use naming convention in the method name to write the query.

When Spring inspects your interface and sees the method findByLastName(String lastName), it associates the method name to a query which does a find with a match by lastName field. So, it generate a JPQL query like that :

select c from Customer c where c.lastName=%lastName

and it sets the lastName param with the effective parameter used when the method is call.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Thanks for explaining that. I was just wondering if there was a way to use the repository in the same way that CommandLineRunner demo() does, like repository.save(whatever); – Smithers Nov 27 '16 at 08:09
  • Of course, you can, CommandLineRunner is only a way of doing it. So to do it, inject the bean by declaring `@Bean CustomerRepository repository` in any class managed by Spring (any Spring Bean : controller, service, etc...) and you could use the repository bean and call its methods – davidxxx Nov 27 '16 at 08:12
  • So declare it as a method? Because just @Bean CustomerRepository repostory; in my controller tells me a bean is disallowed for this location – Smithers Nov 27 '16 at 08:19
  • Not as a method, as explained it is an example. You should edit your question with the code. – davidxxx Nov 27 '16 at 08:32
  • I was actually able to get it using the first answer in: http://stackoverflow.com/questions/36713663/how-to-fix-the-crudrepository-savejava-lang-object-is-no-accessor-method-in-sp by declaring customerrepistory with a @Autowired annotation. – Smithers Nov 27 '16 at 19:10