Does Crud Repository has saveAll method that works? - spring-data-jpa

I am trying to use CRUDRepository for my development project. I have seen in many posts that CRUD Repository do support saveAll method which allows to save a list of object in the database. But when I am using it, It is giving me an error that saveAll property is not found
Here is the detailed error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BinaryPartCRUDRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query method public abstract java.util.List xxx.xxx.xx.xxxx.repository.BinaryPartCRUDRepository.saveAll(java.util.List)! No property saveAll found for type BinaryPart!
Here is my code.
public interface BinaryPartCRUDRepository extends CrudRepository<BinaryPart, Long> {
BinaryPart save(BinaryPart binaryPart);
List<BinaryPart> saveAll(List<BinaryPart> binaryParts);
}
The save Function is working. But saveAll is not.
I have also tried to use the Persistence manager to do the batch save. But having null object while doing JUnit Testing. So I am preferring to stay with CRUD Repository. Appreciate any kind of suggestion.

saveAll already there in CrudRepository, so no need to specify your own method for save all in repository interface.
remove this part:
List<BinaryPart> saveAll(List<BinaryPart> binaryParts);
and in your service class , directly call `saveAll method. Remember this method using iterable as param and return value.

The saveAll method has the following signature:
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
You define an additional method with the same name, but a different signature. Spring Data does not know how to create an implementation for that and throws the exception.
Just change your interface to:
public interface BinaryPartCRUDRepository extends CrudRepository<BinaryPart, Long> {}
And you are good to go.

Related

How to create a JpaRepository but NOT using dependency injection

In my application I am currently creating a JpaRepository via the usual mechanism, i.e. by defining an interface like so:
public interface HistoryInfoRepository extends JpaRepository<HistoryInfo, Long>
This works all fine BUT if the DB is not available or not accessible when starting up the application then the creation of the repo bean fails, the injection into the respective service (which receives that repo as an autowired constructor argument) fails and as a consequence my applications main class:
SpringApplication.run(Application.class, args);
fails as well. I.e. the entire application just fails with a gigantic stacktrace.
I would want to make situation a bit more user friendly in that the application at least comes up so far that it is able to display some (hopefully) helpful error message with an explanation and some hints what should be checked for.
That would require to NOT autowire the JpaRepository but create it programmatically, e.g. in said service's constructor but wrapped within some try - catch construct.
I don't want to give up that convenience that the JpaRepository mechanism provides but how can one create such a JpaRepository programmatically when there is only an interface defined and everything else is done automagically by Spring?
Is there some API-call to create such a JpaRepository for a given interface?
I would like to see something like this:
public HistoryInfoService( /* HistoryInfoRepository historyRepo */) {
...
try {
historyRepo = createJpaRepositoryFromInterface(HistoryInfoRepository.class);
} catch (Exception ex) {
// inform user about missing or non-reachable DB server and suggest remedies...
}
...
}
Here I commented away the constructor argument which is normally provided via auto-wiring, but instead I want to create the JpaRepository using some method-call. That would allow me to properly react to the failed Repo-creation as indicated by the comment in the catch clause.
I searched for something like that but I must have been using the wrong search terms and found nothing so far. Any hints?

Solution for "Failed to create query for method" findOne

So, I was getting this exception when starting up my app that uses spring-data-jpa 2.0.3
java.lang.IllegalArgumentException: Failed to create query for method public abstract package.Entity package.repositories.EntityRepository.findOne(java.lang.Integer)! No property findOne found for type Entity!
So, the issue was that my EntityRepository extends CrudRepository. CrudRepository already provides the findOne() method. A previous developer had duplicated the method in our EntityRepository interface. By removing the duplicate method, everything worked.
I also had to remove the findAll() : List methods. In this case, it wasn't a straight removal, because the CrudRepository returns Iterable instead. Still an easy fix.

Disable query creation from method name - use of projections

I would like to use the Spring Data Projection technique in order to extract from a table only some fields (and not all fields of the table).
As described in the documentation (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections) I created a simple interface, for example:
interface NamesOnly {
String getFirstname();
String getLastname();
}
But I have some problems to use it.
Problem 1:
First of all, I would like to use the name findAll() to create a query that finds all rows with only two fields (firstName and lastName):
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
List<NamesOnly> findAll();
}
But in this case I have these errors (maybe because findAll() is a method of the JpaRepository):
implements org.springframework.data.jpa.repository.JpaRepository.findAll
The return type is incompatible with JpaRepository.findAll()
Problem 2:
Ok, so I try to change the name of the method to findAllOnlyNames():
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
List<NamesOnly> findAllOnlyNames();
}
But now I have this error:
Caused by:
org.springframework.data.mapping.PropertyReferenceException: No
property findAllOnlyNames found for type Persona!
Because Spring tries to create a query from the name.
1) Could it be possible to reuse the method name findAll() without having problems with JpaRepository?
2) Could it be possible to turn off the query creation from the method name (only for some queries, not for all projects or repositories)?
You are on the right track, your findAll() is in conflict with the ones specified on the existing Spring Data interfaces and you can rename it (as you tried) but it still has to be a name that is compatible with the query derivation mechanism. Try this instead:
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
List<NamesOnly> findAllOnlyNamesBy();
}
This part of the Spring Data JPA documentation explains how the query creation process works:
The mechanism strips the prefixes find…By, read…By, query…By, count…By, and get…By from the method and starts parsing the rest of it.
So you just need to add the By keyword in the method name, anything after that keyword is treated as a condition, in this case there is no condition so it fetches everything.
To disable the query derivation from the method name you would need to add an #Query(...) annotation to the method and specify either a JPA or native query instead.
You can specify an explicit query rather than rely on it being derived from the method name.
#Repository
public interface PersonaRepository extends JpaRepository<Persona, Long> {
#Query("select p from Persona p")
List<NamesOnly> findAllOnlyNames();
}
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
Overriding findAll() (even in the unlikely event it is possible) is probably a bad idea.

Spring MVC calling webservice endpoint from the browser

I want to be able to call my web service directly from the browser. Calling it from a HTTPClient via the web browser is OK, but if i try and call it directly via the browser I get the following error:
SEVERE: [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Could not instantiate JAXBContext for class [class com.mycompanay.MyClass]: 8 counts of IllegalAnnotationExceptions; nested exception is com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 8 counts of IllegalAnnotationExceptions
com.mycompany.MyInterface is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
com.mycompany.myInteface
at private java.util.List com.mycompanay.MyClass.values
at com.mycompanay.myClass
#XmlAttribute/#XmlValue need to reference a Java type that maps to text in XML.
this problem is related to the following location:
I've tried to reference the implmentation class via the #XMLElement annotation but i'm getting the same error:
public MyClass {
#XmlElement(type=MyInterfaceImpl.class, name="values")
private List<MyInterface> values;
#XmlElement(type=MyInterfaceImpl.class, name="values")
public void getValues() {
return values;
}
}
You were correct to use the #XmlElement annotation to specify the implementation type. The problem is still occurring because by default JAXB will treat public properties as mapped. This is why it is still trying to process the interfaces. Since you have annotated tr field you can add XmlAccessorType(XmlAccessType.FIELD) to your class.
For More Information
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
http://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html

cannot find my bean using the InitialContext.lookup() method

I have tried to use struts 1.3 API to make a small application with EJB 3.0. Unfortunatelly i cannot use the #EJB annotation to call my bean object from inside my action class. I have solved this problem using different workarounds ( the first one is to use my global jndi name of my bean and the other is to call another class first and use the #EJB annotation from that class). Still these two workarounds have significant disadvantages. I would like to call my EJB directly from my action class. I have read plenty examples using the "java:comp/env/beanName" JNDI name but still haven't figure out how to do it and get name not found axception.
Let the full name of the local EJB class be the com.ejb.myEjbPackage.MyEJBLocal, how can i call it using the context lookup? (can i do it without modifying any of the web.xml and sun-web.xml descriptors?)
I am using glassfish server and Netbeans IDE.
Thank you in advance
#EJB won't work in a standard pojo it can only be done in a managed object (i.e. another session bean)
So...
Here's your bean
#Stateless(mappedName="beanName")
public class beanName implements beanNameRemote {
Here's your lookup
Context context = new InitialContext(); //default lookup pulls from jndi properties file
context.lookup("beanName");
You can do some further reading on the mappedName to see if you want to use it or not.
I found the answer :
If you cannot use the EJB annotation in the class you want to call the bean then :
If you don't want to mess with XML descriptors to define your bean , you have to do it in the bean class itself.
Hence i used the following annotation in the GameBean class
#Stateless
#EJB(name="ejb/GameBean",beanInterface=GameBeanLocal.class,beanName="GameBean")
public class GameBean implements GameBeanLocal {.....
The beanName is optional. The annotation must be declared in the line ABOVE the declaration of the class.
Then, in order to call the bean from the other class you can do
InitialContext ic = new InitialContext();
ic.lookup("java:comp/env/ejb/GameBean");