Getting class cast exception when doing a POST request using JAX-RS with hibernate backend - jax-rs

I have a simple User POJO class, its definition is as follows:
package models;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
#Table(name="USER",uniqueConstraints={#UniqueConstraint(columnNames="email")})
public class User {
#XmlElement
private String name;
#Id
#XmlElement
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#XmlElement
private String email;
#XmlElement
private int age;
#Override
public String toString() {
return "User [name=" + name + ", id=" + id + ", email=" + email + ", age=" + age + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
and my resource mapping is as follows:
#POST
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/Person")
public Response insertPerson(User user) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
int uid = (Integer)session.save(user);
tx.commit();
session.close();
return Response.status(201).entity(uid).build();
}
When i do a post request using PostMan i am getting this exception on server:
Dec 20, 2015 9:44:42 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/expenseManagement] threw exception [Exception [EclipseLink-6065] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.QueryException
Exception Description: Cannot add the object [User [name=manjunath, id=100, email=manjunath#gmail.com, age=15]], of class [class models.User], to container [class models.User].
Internal Exception: java.lang.ClassCastException: models.User cannot be cast to java.util.Collection] with root cause
java.lang.ClassCastException: models.User cannot be cast to java.util.Collection
I have provided message body readers as well, I don't know where i am going wrong, can someone please help.

The content you send is surrounded by [ and ] marking it an array, not an object. Try sending only this String:
{"name":"manjunath", "age":15, "id":100, "email":"manjunath#gmail.com"}
Good Luck

Related

Retrieve results JAX-RS + Jersey + Jackson

I have this entity class
#Entity
#XmlRootElement
#Table(name="user")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id_user", unique=true, nullable=false)
private String idUser;
#Column(nullable=false, length=50)
private String docnum;
#Column(nullable=false, length=50)
private String email;
#Column(nullable=false, length=50)
private String firstname;
#Column(nullable=false, length=50)
private String lastname;
#Column(nullable=false, length=45)
private String pwd;
//bi-directional many-to-many association to Transaction
#ManyToMany
#JoinTable(
name="transaction_users"
, joinColumns={
#JoinColumn(name="user", nullable=false)
}
, inverseJoinColumns={
#JoinColumn(name="transaction", nullable=false)
}
)
private List<Transaction> transactions;
public User() {
}
public String getIdUser() {
return this.idUser;
}
public void setIdUser(String idUser) {
this.idUser = idUser;
}
public String getDocnum() {
return this.docnum;
}
public void setDocnum(String docnum) {
this.docnum = docnum;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstname() {
return this.firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return this.lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public List<Transaction> getTransactions() {
return this.transactions;
}
public void setTransactions(List<Transaction> transactions) {
this.transactions = transactions;
}
}
generated from a database table. Then i have this rest service
#Path("service/2.0")
public class ServiceTest {
#GET
#Path("/users")
#Produces(MediaType.APPLICATION_JSON)
public Response getUser() {
EntityManager entityManager = EntityManagerUtil.getEntityManager();
entityManager.getTransaction().begin();
Query q = entityManager.createQuery("SELECT u FROM User u");
#SuppressWarnings("unchecked")
List<User> listOfUser = q.getResultList();
System.out.print(listOfUser);
return Response.ok(listOfUser).build();
}
I'm (supposed) to be using the jackson API to handle json but i'm not using maven. For this reason, i've added in my buildpath the following .jars:
jackson-annotations-2.9.3.jar
jackson-core-2.9.3.jar
jackson-databind-2.9.3.jar
jackson-jaxrs-base-2.9.3.jar
jackson-module-jaxb-annotations-2.9.3.jar
jersey-media-json-jackson-2.26.jar
jackson-jaxrs-json-provider-2.9.3.jar
Then i have an ApplicationConfig.java class
package prova;
import com.fasterxml.jackson.jaxrs.json.*;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ApplicationPath;
#ApplicationPath("rest")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("com.fasterxml.jackson.jaxrs.json");
packages("prova");
}
}
When i try to submit a GET request with postman, i obtain an "HTTP 500 internal server error" with the description:
"The server encountered an unexpected condition that prevented it from fulfilling the request."
While from the eclipse console i can see
[EL Fine]: sql: 2017-12-16 17:44:54.251--ServerSession(1869059368)--
Connection(771012214)--Thread(Thread[http-nio-8080-exec-80,5,main])--
SELECT id_user, DOCNUM, EMAIL, FIRSTNAME, LASTNAME, PWD FROM user
[prova.User#3c713cb0, prova.User#49e51730, prova.User#d9ecdd7,
prova.User#383fe468]dic 16, 2017 5:44:54
PM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWr
iterInterceptor aroundWriteTo
GRAVE: MessageBodyWriter not found for media type=application/json,
type=class java.util.Vector, genericType=class java.util.Vector.
So what i can deduce is that the query is correctly executed and it returns an array of 4 object (prova is the name of my entity manager) but then i have the GRAVE:MessageBodyWriter Error
What the hell i'm not doing correctly?why i can not retrieve my JSON data?
Thanks
UPDATE
Following the advice, i've modified the GET resource into
#GET
#Path("/users")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getUser() {
return String.valueOf(10+4);
}
and submitting the GET request gives me the expected JSON answer from Postman "14"....
Can the problem be the conversion of a List into Json?if yes, what to do?
Thanks
UPDATE 2
I've edited the code of the REST resource in this way:
#GET
#Path("/users")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getUser() {
EntityManager entityManager = EntityManagerUtil.getEntityManager();
entityManager.getTransaction().begin();
Query q = entityManager.createQuery("SELECT u FROM User u");
List<User> listOfUser = q.getResultList();
System.out.print(listOfUser);
if (listOfUser.isEmpty()) {
System.out.println("VOID LIST");
entityManager.close();
return String.valueOf(2);
}
for (User user : listOfUser) {
System.out.println(user.getFirstname());
System.out.println("---");
}
return String.valueOf(3);
}
The postman Output is "3" so, everything fine while the consoloe output is:
[EL Fine]: sql: 2017-12-17 13:48:33.214--ServerSession(286337061)--
Connection(2132504260)--Thread(Thread[http-nio-8080-exec-2,5,main])--
SELECT id_user, DOCNUM, EMAIL, FIRSTNAME, LASTNAME, PWD FROM USER
[prova.User#2d3017ff, prova.User#6361d00, prova.User#7ab0944a,
prova.User#5945162f]
matteo
---
tony
---
bruce
---
peter
---
which is perfectly consistent with what i have in the table of the DB... :(
Try to convert your response entity in an array of users. There is proper equivalent for array in json.
Other way ist to have a wrapper class for your list of users.
#XmlType
#XmlRootElement
class Wrapper {
#XmlElement
List<User> users;
}
Return this in your response.

Apache Ignite javax.cache.CacheException: Indexing is disabled for cache

When I run the following code, an exception that Apache Ignite javax.cache.CacheException: Indexing is disabled for cache is thrown.
Not sure where the problem lies. Could someone help? Thanks!
package com.xyz.ignite.sqlgrid;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder;
import javax.cache.Cache;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.Arrays;
import org.apache.ignite.cache.query.annotations.QuerySqlField;
class Person {
#QuerySqlField
private String name;
#QuerySqlField
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class IgniteSQLQueryTest {
public static void main(String[] args) throws Exception {
String configPath = "D:/apache-ignite-fabric-1.7.0-bin/config/default-config.xml";
Ignite ignite = Ignition.start(configPath);
CacheConfiguration<Integer, Person> cfg = new CacheConfiguration<Integer, Person>();
cfg.setName("person_cache");
cfg.setIndexedTypes(Integer.class, Person.class);
Cache cache = ignite.getOrCreateCache(cfg);
String cacheName = cache.getName();
for (int i = 1; i <= 100; i++) {
Person p = new Person();
p.setAge(i);
p.setName("name-" + i);
cache.put(i, p);
}
for (int i = 1; i <= 100; i++) {
System.out.println("Cache get:" + cache.get(i));
}
Class.forName("org.apache.ignite.IgniteJdbcDriver");
Connection conn = DriverManager.getConnection(String.format("jdbc:ignite:cfg://cache=%s#file:///%s", cacheName, configPath));
ResultSet rs = conn.createStatement().executeQuery("select name from Person");
while (rs.next()) {
String name1 = rs.getString(1);
System.out.println(name1);
}
ignite.close();
}
}
an exception occurred,the exception message is:
Exception in thread "main" java.sql.SQLException: Failed to query Ignite.
at org.apache.ignite.internal.jdbc2.JdbcStatement.executeQuery(JdbcStatement.java:115)
at com.xyz.ignite.sqlgrid.IgniteSQLQueryTest.main(IgniteSQLQueryTest.java:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:88)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:613)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: javax.cache.CacheException: Indexing is disabled for cache: person_cache. Use setIndexedTypes or setTypeMetadata methods on CacheConfiguration to enable.
at org.apache.ignite.internal.processors.cache.IgniteCacheProxy.validate(IgniteCacheProxy.java:732)
at org.apache.ignite.internal.processors.cache.IgniteCacheProxy.query(IgniteCacheProxy.java:664)
at org.apache.ignite.internal.jdbc2.JdbcQueryTask.call(JdbcQueryTask.java:158)
at org.apache.ignite.internal.jdbc2.JdbcStatement.executeQuery(JdbcStatement.java:102)
Looks that I find where the problem lies.The Person Pojo should be
class Person implements Serializable {
#QuerySqlField(index = true)
private String name;
#QuerySqlField(index = true)
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
The QuerySqlField annotation should add an index = true parameter

Spring-data-solr config

i met a problem in Studying with Spring data solr,this is my Configuration Class:
#Configuration
#EnableSolrRepositories(basePackages={"cn.likefund.solr.repository"}, multicoreSupport=true)
public class SolrContext {
static final String SOLR_HOST = "http://192.168.11.157:8080/solr";
#Bean
public SolrClient solrClient() {
return new HttpSolrClient(SOLR_HOST);
}
}
and this is my Repository:
package cn.likefund.solr.repository;
import java.util.List;
import org.springframework.data.solr.repository.SolrCrudRepository;
import cn.likefund.solr.model.Activity;
public interface ActivityRepository extends SolrCrudRepository<Activity, String>{
List<Activity> findByName(String name);
}
when I start the application,the message in console is this
error
When I delete the method findByName in the repository,the application start with no problem, i just want to the method findByName worked,anybody know what should i do with this problem?
here is the Activity Class:
#Entity
#SolrDocument(solrCoreName ="core_activity")
public class Activity implements Serializable{
private static final long serialVersionUID = 1566434582540525979L;
#Id
#Field(value = "id")
private String id;
#Field(value = "CREATEDT")
private String createdt;
#Indexed
#Field(value = "NAME")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreatedt() {
return createdt;
}
public void setCreatedt(String createdt) {
this.createdt = createdt;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
So, obviously the CrudRepository is not created .
when you delete the findByName, can you manually query your repo ? (just to be sure the problem comes from the method, and not the SOLR schema)
have you tried to annotate annotate the method to explicitly set the query ? Something like
#Query("NAME:?0")
List findByName(String name);

Glassfish - cannot remove entity using JPA

In my exploration of JPA, I have the code below (which I understand should not be used in production). Running my code produces the following error:
java.lang.IllegalStateException:
Exception Description: Cannot use an EntityTransaction while using JTA.
The Resource code is as follows:
#Path("users")
public class UsersAPI {
#Context
UriInfo uriInfo;
#Inject
UserBean accountsBean;
#GET
#Path("deduplicate")
public Response deduplicateDB(){
List<UserProfile> profiles = accountsBean.getAll();
int profilesNum = profiles.size();
for(int i = 0; i < profilesNum; ++i){
for(int k = 0; k < profilesNum; ++k){
if(i != k){ //if it's not the same profile
if(profiles.get(i).getUsername().equals(profiles.get(k).getUsername())){
accountsBean.remove(profiles.get(k));
profiles.remove(k);
}
}
profilesNum = profiles.size();
}
}
return Response.ok().build();
}
}
The code in the ProfilesBean is as follows:
#Local
#Stateless
public class UserBean {
#PersistenceContext
EntityManager eManager;
public void save(UserProfile data){
eManager.merge(data);
}
public void remove(UserProfile data){
eManager.getTransaction().begin();
eManager.remove(data);
eManager.getTransaction().commit();
}
public List<UserProfile> getAll(){
Query q = eManager.createQuery("SELECT profile FROM Users profile");
return (List<UserProfile>)q.getResultList();
}
}
Here is the code for the Entity class:
#Entity(name="Users")
public class UserProfile {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
Long id;
String password;
#Column(unique=true)
String username;
public UserProfile(String username){
setUsername(username);
}
public UserProfile(){
this(null);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
It seems like the error comes from my misusing the platform somehow. How can I fix this code and not misuse the platform in the future?
If you are using JTA as transaction-type in persistence.xml file just leave JTA handles your transactions
public void remove(UserProfile data){
eManager.remove(eManager.merge(data));
}
UPDATE:
In a more clear solution you could use "find", but you need to provide the object id
public void remove(UserProfile data){
UserProfile e = em.find(UserProfile.class, data.getId());
eManager.remove(e);
}

Creating Envers custom revision entity

I'm trying to setup audit for our project.
I started from the default configuration which works fine.
The next step is to store the user which has made changes.
Following the manual I created custom entity revision:
package com.csbi.samples.utils.audit;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.Date;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
import org.hibernate.envers.RevisionEntity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;
#Entity
#Table(name="REVISIONS")
#RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity implements Serializable {
private static final long serialVersionUID = -1255842407304508513L;
#Id
#GeneratedValue
#RevisionNumber
private int id;
#RevisionTimestamp
private long timestamp;
private String username;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Transient
public Date getRevisionDate() {
return new Date(timestamp);
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public boolean equals(Object o) {
if(this == o) return true;
if(!(o instanceof CustomRevisionEntity)) return false;
CustomRevisionEntity that = (CustomRevisionEntity) o;
if(id != that.id) return false;
if(timestamp != that.timestamp) return false;
if(timestamp != that.timestamp) return false;
if(username != that.username) return false;
return true;
}
public int hashCode() {
int result;
result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}
public String toString() {
return "DefaultRevisionEntity(user = " + username + "id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
}
}
And also custom listener:
package com.csbi.samples.audit;
import org.hibernate.envers.RevisionListener;
public class CustomRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity;
revision.setUsername("username"); //for testing
}
}
Here is some lines from log:
DEBUG: org.hibernate.envers.configuration.metadata.AuditMetadataGenerator -
Generating first-pass auditing mapping for entity
com.csbi.samples.domain.Property.
DEBUG:
org.hibernate.envers.configuration.metadata.AuditMetadataGenerator -
Generating second-pass auditing mapping for entity
com.csbi.samples.domain.Property.
INFO : org.hibernate.cfg.HbmBinder
- Mapping class: com.csbi.samples.domain.Property_AUD -> PROPERTIES_AUD
INFO : org.hibernate.cfg.HbmBinder - Mapping class:
org.hibernate.envers.DefaultRevisionEntity -> REVINFO
Take a look at the last line of the output.
There is still DefaultRevisionEntity mapped instead of CustomRevisionEntity.
I have no idea what is wrong. Any suggestions?
Solved. Entity is not in scanned by Hibernate directory.