Spring-Data-Rest: countBy*** method/Query not working - spring-data-jpa

I am learning the Spring-Data-Rest and trying to add the countBy*** functionality in my Customer Repository. However, when I try to make the api call:
//<app>/customers/search/countByFirstnameUsingQuery?firstname=Dave, or
//<app>/customers/search/countByFirstname?firstname=Dave I get 500 Internal Server Error.
Below is how my repository looks like
public interface CustomerRepository extends JpaRepository<Customer, Long>{
Customer findByEmailAddress(#Param("emailAddress") EmailAddress emailAddress);
#Query("select c from Customer c where c.firstname = :firstname")
Customer findByFirstNameUsingQuery(#Param("firstname") String firstname);
public long countByFirstname(#Param("firstname") String firstname);
#Query("select count(c) from Customer c where c.firstname = :firstname")
Long countByFirstnameUsingQuery(#Param("firstname") String firstname);
}
Below is my Customer class
#Entity
public class Customer extends AbstractEntity {
private String firstname, lastname;
#Column(unique = true)
private EmailAddress emailAddress;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "customer_id")
private Set<Address> addresses = new HashSet<Address>();
There is no exception coming on the server. Below is all what comes to the server logs
However, below is what comes to the logs.
2014-05-08 13:02:05,551 DEBUG rest.webmvc.RepositoryRestHandlerMapping: 219 - Looking up handler method for path /customers/search/countByFirstname
2014-05-08 13:02:05,567 DEBUG rest.webmvc.RepositoryRestHandlerMapping: 226 - Returning handler method [public org.springframework.http.ResponseEntity<org.springframework.hateoas.Resources<?>>
org.springframework.data.rest.webmvc.RepositorySearchController.executeSearch(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.web.context.request.WebRequest,java.lang.String,org.springframework.data.domain.Pageable
Please let me know if any further details required.
Any input on the above shall be much appreciated.
When I access, I gets "500 Internal Server Error".
To me it looks that spring data rest is not supporting exposing count as rest api.

Related

Spring Data JPA: How do i retrieve a list on an entity while filtering its field for first occurrence

I want to retrieve a list of all messages from other users (senders) to a user who is a receiver. But i want to only retrieve the first occurrence from each sender.
For example if sender 2 sent 4 messages to user1, only one gets picked(based on the time created) and gets added to the list.
How do i achieve this:
this is my entity class :
#Entity
#Table(name = "Message")
public class Message extends DefaultEntity {
#Valid
#ManyToOne(targetEntity = User.class)
#JoinColumn(name="sender")
private User sender;
#Valid
#ManyToOne(targetEntity = User.class)
#JoinColumn(name="receiver")
private User receiver;
#NotNull
private String message;
#Enumerated(EnumType.STRING)
private MessageStatus messageStatus;
private Boolean isRead;
}

how to develop JPA bi-directional entities in spring toot

I am new to spring boot and jpa/hibernate, please bear my inaccurate usage of the terminologies.
I have two entities: book and address. A book is published in a certain city which is stored in "address", a "address" can publish multiple books.
The DB schema for book is: id, name, author, price, addressid
schema for address: addressid, addressCountry, addressCity
The entity for book:
#Entity
#Table(name = "test_book")
public class Book implements Serializable {
private static final long serialVersionUID = 8025948150436422040L;
#Id
long id;
#Column(name = "name")
String name;
#Column(name = "author")
String author;
#Column(name = "price")
long price;
#ManyToOne
#JoinColumn(name = "addressid")
private Address address;
...//getter and setter
The entity for address
#Entity
#Table(name = "test_address")
public class Address implements Serializable{
private static final long serialVersionUID = -3541059157210384355L;
#Id
#Column(name= "addressid")
private long addressId;
#Column(name="addresscountry")
private String addressCountry;
#Column(name="addresscity")
private String addressCity;
#OneToMany(mappedBy = "address")
private Collection<Book> books;
...//getter setter
But when I call the Restful service, I get infinite loop...
[{"id":11,"name":"Java Book","author":"Jame Gosling","price":100,"address":{"addressId":1,"addressCountry":"China","addressCity":"Shanghai","books":[{"id":11,"name":"Java Book","author":"Jame Gosling","price":100,"address":...
I did some search. And my request is:
when I search a book, I can get the information: id, name, author, price, address..
And also I can query a address to get all the books the city published.
When I add Json Annotation #JsonManagedReference in address and #JsonBackReference in book entity, I can query book but cannot get address information.
Could you please help how to solve the problems? Thank you very much.
You can ignore the #JsonIgnore on getter for books. This will exclude the Collection<Book> books property from serialization the Address.
Link : JacksonAnnotations - Faster XML Wiki
Example:
#JsonIgnore
public Collection<Book> getBooks() {
...
}
#JsonIgnore
The Jackson annotation #JsonIgnore is used to tell Jackson to ignore a
certain property (field) of a Java object. The property is ignored
both when reading JSON into Java objects, and when writing Java
objects into JSON.
In your case this is happening as there is bidirectional relationship and so it will go into loop. To stop this you need to provide JsonIgnore
And so your code will be like :
-> The entity for address
#Entity
#Table(name = "test_address")
public class Address implements Serializable{
private static final long serialVersionUID = -3541059157210384355L;
#Id
#Column(name= "addressid")
private long addressId;
#Column(name="addresscountry")
private String addressCountry;
#Column(name="addresscity")
private String addressCity;
#OneToMany(mappedBy = "address")
#JsonIgnore
private Collection<Book> books;

JPA Exception- Can not find constructor for <Class> with argument types "[class java.lang.String, class java.lang.String]" to fill data

I use jBoss Fuse 6.1.0 with blueprint DSL with openJPA. I use Container Managed transaction (JTA) and transaction managed by Aspects that handles Commit and Rollback as of now
I have following Classes that are JPA entities.
#Entity
#Table(name="CLIENT")
#NamedQuery(name="Client.findAll", query="SELECT c FROM Client c")
public class Client implements Serializable {
private static final long serialVersionUID = 1L;
//Had to add this for avoiding exception. And it works as expected
//Dummy constructor for JPA - Workaround
public Client(String s1, String s2){}
#Column(name="requestid", unique=true,nullable=false)
private String requestId;
#Id
#Column(name="clientid", unique=true, nullable=false, length=128)
private String clientId;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="REQUESTID", nullable=false)
private RoccoRequest roccoRequest;
//bi-directional One-To-Many association to ClientGroup
#OneToMany(mappedBy="client",fetch=FetchType.LAZY)
private List<ClientGroup> clientGroups;
....
,...
...
}
#Entity
#Embeddable
#Table(name="CLIENTGROUP")
#NamedQuery(name="ClientGroup.findAll", query="SELECT c FROM ClientGroup c")
public class ClientGroup implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ClientGroupPK id;
#Column(length=32)
private String type;
#Column(name="clientid", length=128)
private String clientId;
//bi-directional many-to-one association to Client
#ManyToOne(fetch=FetchType.EAGER)
#MapsId("clientid")
#JoinColumn(name="CLIENTID", nullable=true, insertable=false, updatable=false)
private Client client;
..
.
.
.
}
#Entity
#Table(name="ROCCOREQUEST")
#NamedQuery(name="RoccoRequest.CHECK_EXISISTING_CLIENT_DETAILS",
query="SELECT r FROM RoccoRequest r JOIN r.client c WHERE c.crmId = :crmId")
public class RoccoRequest implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="requestid", unique=true, nullable=false, length=128)
private String requestId;
#OneToOne(mappedBy="roccoRequest", fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private Client client;
..
..
..
CriteriaQuery<Client> criteriaQuery = criteriaBuilder.createQuery(Client.class);
Root<Client> clientRoot = criteriaQuery.from(Client.class);
//Join the Client table with the RoccoRequest table
final Join<Client, RoccoRequest> clientRoccoJoin = clientRoot.join(Client_.roccoRequest,JoinType.INNER);
final Path<String> _requestStatus = clientRoccoJoin.get(RoccoRequest_.statusCode);
final Path<String> _requestId = clientRoccoJoin.get(RoccoRequest_.requestId);
final Predicate _crmIdPredicate = criteriaBuilder.equal(clientRoot.get(Client_.crmId), CRMId);
criteriaQuery.multiselect(_requestId,_requestStatus);
criteriaQuery.where(_crmIdPredicate);
//Get list of details of existing requests for the client with the request type as ACO
clientDetails = entityManager.createQuery(criteriaQuery).getResultList();
if(null != clientDetails) for(Client clientDetail : clientDetails){
StatusBO statusDetails = new StatusBO();
statusDetails.setCode((clientDetail.getRoccoRequest().getStatusCode()));
PreInitiationBO preinitiateDetails = new PreInitiationBO();
preinitiateDetails.getCaseHeader().setRequestId(requestId);
preinitiateDetails.setStatus(statusDetails);
exisitngRequestInfo.add(preinitiateDetails);
}
I have did some Criteria fetching of the entities. But I'm getting an exception as follows:
Can not find constructor for "class com.xxx.xxx.model.Client" with
argument types "[class java.lang.String, class java.lang.String]" to
fill data.
Why does JPA expect an argument Constructor? It has anything to do with the association? I tried removing the OneToMany relationship but I still get the error.
Please note that I have added a 2 argument constructor that makes no sense to me. But it works if it's given. log root level has Debug enabled. It has very less information on exception.
Please help.
As JBNizet pointed out,
I was making a dumb mistake by adding multiselect with two Strings but was having a CrtieriaQuery of type Client.class.
This can either be solved by removing the multiselect(Not in my case) or by Making the CriteriaQuery and other types with Tuples.class instead of Client.class and loop through the Tuples and get as tuple.get(0) etc.
Problem resolved. Thanks #Neil and #JBNizet

client PersistenceCapable NoClassDefFoundError while serializing Entity object from server to client using gwt

I'm using apache open JPA to access my db at the server side. I'm trying to call from my gwt client to the server in order to retrive an entity object, but this requests always fails with the error message:NoClassDefFoundError org/apache/openjpa/enhance/PersistenceCapable.
I tried defining my enhanced entity classes at the gwt.xml file and it did not helped:
<set-configuration-property name="rpc.enhancedClasses" value="com.jobsin.domain.SystemUser,com.jobsin.domain.Keyword,com.jobsin.domain.Job">/
My server function:
public SystemUser getCurrentUser()
throws InvalidUser{
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
HttpSession session = httpServletRequest.getSession();
SystemUser user=null;
Cookie[] cookies = httpServletRequest.getCookies();
SocialNetworkCookie cookie = network.generateCookieObject();
if(!cookie.init(cookies)){
session.invalidate();
throw new InvalidUser(); // no user was connected, user need to login
}
//try get user details from db
EntityManager em = factory.createEntityManager();
SystemUserDAOImpl userdao = new SystemUserDAOImpl(em);
user = userdao.findUserByNetworkId(cookie.getMemberId());
//make user detach
em.close();
return user;
}
SystemUser Class :
#Entity
public class SystemUser implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -1673271845552139219L;
#Id
#GeneratedValue
private long id;
#NotNull
private String firstName;
#NotNull
private String lastName;
#NotNull
#Column(unique=true)
private String email;
#Temporal(TemporalType.TIMESTAMP)
private Date lastSearch;
#ManyToMany(cascade = CascadeType.ALL)
private Set<Job> jobs = new HashSet<Job>();
#ManyToMany(cascade = CascadeType.ALL)
private Set<Keyword> keywords = new HashSet<Keyword>();
}
The easiest solution would be to add the OpenJPA binaries to the GWT client classpath.

JPA Query Many To One nullable relationship

I have the following entities and would like to seek help on how to query for selected attributes from both side of the relationship. Here is my model. Assume all tables are properly created in the db. JPA provider I am using is Hibernate.
#Entity
public class Book{
#Id
private long id;
#Column(nullable = false)
private String ISBNCode;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = false)
private Person<Author> author;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
private Person<Borrower> borrower;
}
#Inheritance
#DiscriminatorColumn(name = "personType")
public abstract class Person<T>{
#Id
private long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Info information;
}
#Entity
#DiscriminatorValue(PersonType.Author)
public class Author extends Person<Author> {
private long copiesSold;
}
#Entity
#DiscriminatorValue(PersonType.Borrower)
public class Borrower extends Person<Borrower> {
.....
}
#Entity
public class Info {
#Id
private long id;
#Column(nullable=false)
private String firstName;
#Column(nullable=false)
private String lastName;
......;
}
As you can see, the book table has a many to one relation to Person that is not nullable and Person that is nullable.
I have a requirement to show, the following in a tabular format -
ISBNCode - First Name - Last Name - Person Type
How can I write a JPA query that will allow me to select only attributes that I would want. I would want to get the attributes ISBN Code from Book, and then first and last names from the Info object that is related to Person Object that in turn is related to the Book object. I would not want to get all information from Info object, interested only selected information e.g first and last name in this case.
Please note that the relation between the Borrower and Book is marked with optional=true, meaning there may be a book that may not have been yet borrowed by someone (obviously it has an author).
Example to search for books by the author "Marc":
Criteria JPA Standard
CriteriaQuery<Book> criteria = builder.createQuery( Book.class );
Root<Book> personRoot = criteria.from( Book.class );
Predicate predicate = builder.conjunction();
List<Expression<Boolean>> expressions = predicate.getExpressions();
Path<Object> firtsName = personRoot.get("author").get("information").get("firstName");
expressions.add(builder.equal(firtsName, "Marc"));
criteria.where( predicate );
criteria.select(personRoot);
List<Book> books = em.createQuery( criteria ).getResultList();
Criteria JPA Hibernate
List<Book> books = (List<Book>)sess.createCriteria(Book.class).add( Restrictions.eq("author.information.firstName", "Marc") ).list();
We recommend using hibernate criterias for convenience and possibilities.
Regards,