ConstraintViolationException in Java RESTful Webservice - web-services

I'm relatively new to JavaEE and web services, however, I'm using netbeans to generate my client and webservice resources. I have a resource "CustomerData" that represents a mysql database table and a value "rewardsPoints" representing a column in that table, however, I am unable to update the value due to a ConstraintViolationException, specifically:
javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'preUpdate'. Please refer to embedded ConstraintViolations for details.
I'm not familiar with the 'preUpdate' callback event, is it something I need to override? I can't seem to figure out exactly why this exception is being thrown, but, as I said, i'm very new to web service programming. Here are my classes:
#Stateless
#Path("customers")
public class CustomerDataFacadeREST extends AbstractFacade<CustomerData> {
#PersistenceContext(unitName = "CustomerPortalPU")
private EntityManager em;
public CustomerDataFacadeREST() {
super(CustomerData.class);
}
#PUT
#Path("{id}")
#Consumes({"application/xml", "application/json"})
public void edit(#PathParam("id") Integer id, CustomerData entity) {
super.edit(entity);
}
#GET
#Path("{id}")
#Produces({"application/xml", "application/json"})
public CustomerData find(#PathParam("id") Integer id) {
return super.find(id);
}
#GET
#Path("addPoints/{id}/{amount}")
#Produces({"text/plain"})
public String addPoints(#PathParam("id") Integer id, #PathParam("amount") int amount) {
CustomerData customer = find(id);
customer.getRewardsPoints(customer.getRewardsPoints() + amount);
em.persist(customer);
edit(customer);
return customer.getRewardsPoints();
}
#Override
protected EntityManager getEntityManager() {
return em;
}
}
And the CustomerData entity class:
#Entity
#Table(name = "tbl_customer_data")
#XmlRootElement
public class CustomerData implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#NotNull
#Column(name = "rewards_points")
private int rewardsPoints;
public CustomerData(Integer id, int rewardsPoints) {
this.id = id;
this.rewardsPoints = rewardsPoints;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public int getRewardsPoints() {
return rewardsPoints;
}
public void setRewardsPoints(int rewardsPoints) {
this.rewardsPoints = rewardsPoints;
}
}
When I try to access the URI:
http://localhost:8080/CustomerPortal/ws/customers/addPoints/1/5
to add 5 points to user with id 1 i get an HTTP 500 error and in the glassfish logs it says
[2013-11-05T03:28:11.733-0500] [glassfish 4.0] [WARNING] [ejb.system_exception] [javax.enterprise.system.container.ejb.com.sun.ejb.containers] [tid: _ThreadID=21 _ThreadName=http-listener-1(3)] [timeMillis: 1383640091733] [levelValue: 900] [[
EJB5184:A system exception occurred during an invocation on EJB CustomerDataFacadeREST, method: public java.lang.String com.webservice.entities.CustomerDataFacadeREST.addPoints(java.lang.Integer,int)]]
[2013-11-05T03:28:11.741-0500] [glassfish 4.0] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=21 _ThreadName=http-listener-1(3)] [timeMillis: 1383640091741] [levelValue: 900] [[
StandardWrapperValve[com.webservice.entities.ApplicationConfig]: Servlet.service() for servlet com.webservice.entities.ApplicationConfig threw exception
javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'preUpdate'. Please refer to embedded ConstraintViolations for details.
Any resources, insight or information regarding this issue would be extremely helpful.

The exception has little to do with web services: it has to do with Bean Validation instead.
In this case, since the Validation fails inside method addPoints (look at the stack trace) the only line that can cause it is when persisting or editing an Entity of type CustomerData. The only constraint you have in that class is that rewardsPoints should not be null. So, that's the cause of the exception.
However there some things that won't work in addPoints method:
You should check that find() method doesn't return a null object.
customer.getRewardsPoints(customer.getRewardsPoints() + amount) never sets the property (does it compile?)
EntityManager.persist() throws exception if the entity already exists. You probably want to remove that line if you only want to edit (update) the entity.
Note: I am not sure that the code you have posted is really compiling and causing that exception. That's probably caused by another version.

Related

Wso2 XACML get custom attributes

I am using Wso2 IS 5.11.0, I have a requirement where I need to fetch the user attributes by calling web-service based.
Below is the sample attribute finder code:
public class CustomPIPAttributeFinder extends AbstractPIPAttributeFinder {
private static final String PIP_NAME = "CustomPIPAttributeFinder";
private static final Set<String> SUPPORTED_ATTRIBUTES;
private static final Log log = LogFactory.getLog(CustomPIPAttributeFinder.class);
static {
SUPPORTED_ATTRIBUTES = new HashSet<String>();
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_ATTRIBUTE_ID);
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_ATTRIBUTE_NAME);
SUPPORTED_ATTRIBUTES.add(CustomPIPConstants.SAMPLE_CATEGORY);
}
#Override
public Set<String> getAttributeValues(URI attributeType, URI attributeId, URI category, String issuer,
EvaluationCtx evaluationCtx) throws Exception {
//code
}
private String retrieveSampleName(String accessToken) {
String sampleName = null;
// TODO: Get the value of the sample name from the sampleID from the datasource
return sampleName;
}
/**
* Since we override the {#link #getAttributeValues(URI, URI, URI, String, EvaluationCtx)} this won't be called.
*/
#Override
public Set<String> getAttributeValues(String subject, String resource, String action, String environment,
String attributeId, String issuer) throws Exception {
throw new UnsupportedOperationException("Method unsupported in the context");
}
public void init(Properties properties) throws Exception {
}
public String getModuleName() {
return PIP_NAME;
}
public Set<String> getSupportedAttributes() {
return SUPPORTED_ATTRIBUTES;
}
}
In the sample code we can fetch only one attribute per request.But how can we return multiple attributes before executing policy or get multiple attributes in one request from custom attribute finder. Is there any way to achieve this flow.
As per above code request attribute find(returns only one) in the example it will increase the overhead as for each attribute lookup we are calling web-service every time as it'll increase overhead.

How to send a property as a string in RestEasy response?

I have a class called Product which has a property called id of type long. Below is the class
public class Product {
private long id;
}
The value of id is beyond the value which javascript can handle. I realized this after seeing the below link
Parse json in javascript - long numbers get rounded
I dont want to declare the field as String in the domain class. But I want to say to RestEasy that it has to send the value as a string in the json response.
How can I do this? I dont want to use any third party api. Is it possible in RestEasy. I have gone through the documentation but did not find any such annotation or may be I did not go through the documentation properly.
Can anyone please help. Thanks all in advance.
If you are using Jackson as JSON Serializer you can extend the JacksonJsonProvider:
#Provider
public class JsonProvider extends org.codehaus.jackson.JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = locateMapper(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
objectMapper.configure(org.codehaus.jackson.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
}
}
If you are using Jettison you can register a custom XmlAdapter:
public class LongAdapter extends XmlAdapter<String, Long> {
#Override
public String marshal(Long id) throws Exception {
if (id == null) {
return "";
}
return id.toString();
}
#Override
public Long unmarshal(String id) throws Exception {
return Long.parseLong(id);
}
}

Enum conversion to String not working on #Indexed unique field

I'm a Neo4j/Spring-data newbie so apologies if this is something obvious but I looked here and there and can't quite figure out if it's a bug or feature.
I'm using SDN 3.1.0 and Neo4j 2.0.4, running in memory for now (for testing).
I have a super simple POJO that I try to save into Neo4j using SDN. It looks like so:
#NodeEntity
public class Weekday {
#GraphId
private Long id;
#Indexed(unique = true)
public DayOfWeek weekdayCode;
}
Everything works beautifully when I make it non-uniquely indexed, or not indexed at all. It works fine with unique constraint when I make it a String as well. (Well, sort of, I'm aware that it doesn't throw an exception but silently updates existing one - this is not perfect but I found JIRA issue related to that). Unfortunately the moment I try to save it as enum with unique constraint I get an exception:
org.springframework.dao.InvalidDataAccessResourceUsageException: Error executing statement MERGE (n:`Weekday` {`weekdayCode`: {value}}) ON CREATE SET n={props} return n; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: Error executing statement MERGE (n:`Weekday` {`weekdayCode`: {value}}) ON CREATE SET n={props} return n; nested exception is java.lang.IllegalArgumentException: [MONDAY:java.time.DayOfWeek] is not a supported property value
at org.springframework.data.neo4j.support.query.CypherQueryEngineImpl.query(CypherQueryEngineImpl.java:61)
at org.springframework.data.neo4j.support.schema.SchemaIndexProvider.merge(SchemaIndexProvider.java:114)
at [...]
Caused by: org.springframework.dao.InvalidDataAccessResourceUsageException: Error executing statement MERGE (n:`Weekday` {`weekdayCode`: {value}}) ON CREATE SET n={props} return n; nested exception is java.lang.IllegalArgumentException: [MONDAY:java.time.DayOfWeek] is not a supported property value
at org.springframework.data.neo4j.support.query.CypherQueryEngineImpl.parseAndExecuteQuery(CypherQueryEngineImpl.java:72)
at org.springframework.data.neo4j.support.query.CypherQueryEngineImpl.query(CypherQueryEngineImpl.java:58)
... 63 more
Caused by: java.lang.IllegalArgumentException: [MONDAY:java.time.DayOfWeek] is not a supported property value
at org.neo4j.kernel.api.properties.PropertyConversion.convertProperty(PropertyConversion.java:107)
at org.neo4j.kernel.api.properties.Property.property(Property.java:51)
at [...]
This, as far as I can see, is because the unique field is put into a map "props", and the contents of the map is not automatically converted so it sends an enum to Neo4j, which obviously it doesn't like.
Is this expected or should I raise a bug with SDN?
If that's expected behaviour, do I have any alternatives other than making the field a String?
I'm not sure if it is a real bug, however I had a similar problem using my own Enum class.
So, you could try something like this:
Create the converters
Register them in neo4j
First create your converters like:
#Component
public class StringToDayOfWeekConverter implements Converter<String, DayOfWeek> {
#Override
public DayOfWeek convert(String source) {
return DayOfWeek.valueOf(source);
}
}
#Component
public class DayOfWeekToStringConverter implements Converter<DayOfWeek, String> {
#Override
public String convert(DayOfWeek source) {
return source.name();
}
}
Then you register the converters, so neo4j can use them:
#Configuration
#EnableNeo4jRepositories("my.repository.package")
#EnableTransactionManagement
public class MyNeo4jConfiguration extends Neo4jConfiguration {
#Autowired
private StringToDayOfWeekConverter stringToDayOfWeekConverter;
#Autowired
private DayOfWeekToStringConverter dayOfWeekToStringConverter;
#Override
protected ConversionService neo4jConversionService() throws Exception {
ConverterRegistry converterRegistry = (ConverterRegistry) super.neo4jConversionService();
converterRegistry.addConverter(stringToDayOfWeekConverter);
converterRegistry.addConverter(dayOfWeekToStringConverter);
return (ConversionService) converterRegistry;
}
}
create an converter extends EnumStringConverter such like this:
package com.noopu.pyramid.domain.model.converter;
import com..pyramid.common.UserType;
import org.neo4j.ogm.typeconversion.EnumStringConverter;
public class UserTypeStringConverter extends EnumStringConverter {
public UserTypeStringConverter ( ) {
super ( UserType.class );
}
}
and used #Converter annotation like under:
package com.noopu.pyramid.domain.model;
import com.noopu.pyramid.common.UserType;
import com.noopu.pyramid.domain.model.converter.UserTypeStringConverter;
import lombok.Data;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.Index;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.typeconversion.Convert;
import java.io.Serializable;
#NodeEntity
#Data
public class User implements Serializable {
private static final long serialVersionUID = 8979348201709416439L;
#GraphId
private Long graphId;
#Index
protected Long id;
#Index(unique = true)
private Long uid;
#Index(unique = true)
private String phone;
#Index
#Convert(UserTypeStringConverter.class)
private UserType type;
}

Table is not creating using JPA 2.0

I am using JPA 2.0 in Netbeans. I am using entities. If my database has no table then it should create table from entities. Here is my code
public class BankServlet extends HttpServlet {
#EJB
private BankServiceBeanRemote bankServiceBean;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int custId = Integer.parseInt(request.getParameter("id"));
bankServiceBean.createCustomers();
Customer cust = bankServiceBean.findCustomer(custId);
response.setContentType("text/html;charset=UTF-8");
....
} //end of processRequest
} //end of class BankServlet
Here is my bean
#Stateless
public class BankServiceBean implements BankServiceBeanRemote {
#PersistenceContext(unitName = "Bank_JPA-ejbPU")
private EntityManager em;
#Override
public void createCustomers() {
Referee r1 = new Referee();
r1.setId(1);
r1.setName("SIR JOHN DEED");
r1.setComments("JUDGE");
em.persist(r1);
Customer c1 = new Customer();
c1.setId(1);
c1.setFirstName("SIMON");
c1.setLastName("KING");
c1.setReferee(r1);
......
}
} //end of class BankServiceBean
Here is my referee entity
#Entity
public class Referee implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String comments;
public Referee() {
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// other getter setters
} //end of class Referee
When i run the code i get following exception
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'dbbank.referee' doesn't exist
Error Code: 1146
Call: INSERT INTO REFEREE (ID, NAME, COMMENTS) VALUES (?, ?, ?)
bind => [3, MICHAEL ELLIS, MAJOR SHAREHOLDER OF THIS BANK]
Query: InsertObjectQuery(pk.mazars.basitMahmood.entity.Referee[id=3])
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
If table doesnot exist then it should create table automatically. Am i doing something wrong?
Thank you
Your assumptions are wrong. Tables are not magically created if they don't exist. Most of the applications use existing databases.
EclipseLink can create the schema for you, but it's not the default. Read this page to know how to enable this feature:
EclipseLink can be used to automatically generate the tables and
database schema for a persistence unit. This is done through the
"eclipselink.ddl-generation" persistence unit property, set to either
"create-tables" or "drop-and-create-tables". The tables and
constraints will be generated for all of the classes defined in that
persistence unit.
You should change your table generation strategy in persistence.xml.
just add these rows to the persistence.xml file :
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
Here is a snippet to add to your persistence.xml to make openjpa create tables for you. This comes in handy when doing in container unit tests using openejb with an in memory database like HyperSQL.
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>

Http 204 error in REST web service (Jersey)

I am using Jersey/Java to develop my REST services. I need to return an XML representation for my CarStore :
#XmlRootElement
public class CarStore {
private List<Car> cars;
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
Here is my Car object :
#XmlRootElement
> public class Car {
private String carName;
private Specs carSpecs;
private Category carCategory;
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public Specs getCarSpecs() {
return carSpecs;
}
public void setCarSpecs(Specs carSpecs) {
this.carSpecs = carSpecs;
}
public Category getCarCategory() {
return carCategory;
}
public void setCarCategory(Category carCategory) {
this.carCategory = carCategory;
}
}
Specs and Category are enums like this :
#XmlRootElement
> public enum Category {
SEDANS, COMPACTS, WAGONS, HATCH_HYBRIDS, SUVS, CONVERTIBLES, COMPARABLE;
}
My resource class is :
#GET
#Produces({MediaType.APPLICATION_XML})
public CarStore getCars()
{
return CarStoreModel.instance.getAllCars();
}
My jersey client is :
WebResource service = client.resource(getBaseURI());
System.out.println(service.path("rest").path("cars").accept(
MediaType.APPLICATION_XML).get(String.class));
I am getting Http 204 error on access alongwith client exception :
com.sun.jersey.api.client.UniformInterfaceException
Any ideas ? Thanks !
EDIT : I have yet not developed the model class...I just initialized some car objects as dummy data and put them in carstore. Showing all the classes here would be very clumsy.
BTW, sorry for writing 204 Error..it is just that I am getting an Exception that led me think so.
I'm guessing the exception is not related to the response code (204) because 204 is a success condition that indicates "No Content."
I believe you are getting a UniformInterfaceException because your getCars() function is not returning an HTTP response body. The root problem is that your Car List isn't being converted into XML by JAXB because it is missing the #XmlElement annotation.
Your getCars() function should be:
#GET
#Produces(MediaType.APPLICATION_XML)
public CarStore getCars() {
// myCarStore is an instance of CarStore
return myCarStore.getCars();
}
and your Car List in CarStore should be defined:
#XmlElement(name="car")
private List<Car> cars;
Is what you're returning in xml format? I'm not sure what getAllCars does but you can use something like Fiddler to help you view the traffic and see what is being returned to the client and whether its in proper format etc
In your client code, is the resource path correct? Make sure getBaseURI is returning a value.
Perhaps try:
Client client = new Client();
WebResource resource = client.resource(getBaseURI());
CarStore carStore = resource.path("/rest/cars").accept(MediaType.APPLICATION_XML).get(CarStore.class);
Aren't you missing a #Path annotation on your resource class?
#GET
#Path("cars")
#Produces({ MediaType.APPLICATION_XML })
public CarStore getCars() {
return CarStoreModel.instance.getAllCars();
}
Check if the URL at which your REST WS is mounted the one you expect by putting a breakpoint in your getCars() method (or putting a System.out.println) to make sure it actually gets called.
It seems there is a hard coded check in Jersey to throw a UniformInterfaceException when a HTTP 204 is returned.
The best solution will be to 'fix' the rest server so it never returns a null. e.g. return an Empty list or a Class with not values set.
Else you will need to catch UniformInterfaceException which is really ugly
if (getStatus() == 204) {
throw new UniformInterfaceException(this);
}
More info here :
http://grepcode.com/file/repo1.maven.org/maven2/com.sun.jersey/jersey-client/1.17.1/com/sun/jersey/api/client/ClientResponse.java#ClientResponse.getEntity%28java.lang.Class%2Cjava.lang.reflect.Type%29