I am trying to create an Jersey application and I would like to pass the output to web browser in Json format. Below are the codes. I can only pass the data in xml format and when I change to "application/json" format, "HTTP Status 500 - Internal Server Error" came out. Any advice? thanks.
import java.net.URISyntaxException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/emp")
public class EmployeeService {
#GET
#Path("/get/{empID}")
#Produces({"application/json"})
public Employee getEmployee(#PathParam("empID") String empID){
Employee employee = new com.rest.employee.model.Employee();
employee.setEmpID(empID);
employee.setName("George");
employee.setEmail("george#gmail.com");
return employee;
}
}
and another java file
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name="employee")
public class Employee {
public String empID;
public String name;
public String email;
#XmlElement(required=true)
public String getEmpID() {
return empID;
}
public void setEmpID(String empID) {
this.empID = empID;
}
#XmlElement(required=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(required=true)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
The code looks 'nearly' fine and works for me as expected, but your Employee should implement Serializable. I can't see any other problem in there for now, so the problem is somewhere else i guess.
You said, that its not working anymore, since you changed from XML to JSON. So i reckon, that you miss a dependency for JSON. Check this ...
But in fact, the missing dependency should not result in an 500. Can it be true, that you have added a ExceptionMapper and that you throw your 500 by yourself?
You need to integrate Jersey with Jackson. Look at this tutorial:
http://examples.javacodegeeks.com/enterprise-java/rest/jersey/json-example-with-jersey-jackson/
Related
I want to build an API for my Employee entity(table) and when I tried a GET request by id or without id in the URL it works. but when I tried a POST, PUT, PATCH, or DELETE request it will be 405 error. And it looks like this for POST request
2021-11-24 18:42:59.517 DEBUG 4756 [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet :"ERROR" dispatch for POST "/error", parameters={}
2021-11-24 18:42:59.520 WARN 4756---[nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
2021-11-24 18:42:59.520 DEBUG 4756 [nio-8080-exec-6]o.s.web.servlet.DispatcherServlet :Exiting from "ERROR" dispatch, status 405
the api-controlle class looks like
package com.miki.pma.api.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.miki.pma.dao.EmployeeRepository;
import com.miki.pma.entity.Employee;
#RestController
#RequestMapping("/app-api/employees")
public class EmployeeApiController {
#Autowired
EmployeeRepository empRepo;
#GetMapping()
public Iterable<Employee> getEmployees(){
return empRepo.findAll();
}
#GetMapping("/{id}")
public Employee getEmployeeById(#PathVariable("id") Long id) {
return empRepo.findById(id).get();
}
#PostMapping(consumes="application/json")
#ResponseStatus(HttpStatus.CREATED)
public Employee create(#RequestBody Employee employee) {
return empRepo.save(employee);
}
#PutMapping(consumes="application/json")
#ResponseStatus(HttpStatus.OK)
public Employee update(#RequestBody Employee employee) {
return empRepo.save(employee);
}
#PatchMapping(value = "/{id}",consumes="application/json")
public Employee partialUpdate(#PathVariable("id") Long id, #RequestBody Employee pathEmployee) {
Employee emp= empRepo.findById(id).get();
if(pathEmployee.getEmail()!= null) {
emp.setEmail(pathEmployee.getEmail());
}
if(pathEmployee.getFirstName()!= null) {
emp.setFirstName(pathEmployee.getFirstName());
}
if(pathEmployee.getLastname()!= null) {
emp.setLastname(pathEmployee.getLastname());
}
return empRepo.save(emp);
}
#DeleteMapping(value="/{id}")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(#PathVariable("id") Long id) {
empRepo.deleteById(id);
}
}
The Employee entity class looks like this
package com.miki.pma.entity;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sun.istack.NotNull;
#Entity
public class Employee {
#Id
#GeneratedValue(strategy= GenerationType.SEQUENCE, generator="employee_seq")
#SequenceGenerator(name = "employee_seq", allocationSize = 1)
private long employeeId;
#NotNull
#Size(min=2, max=50)
private String firstName;
#NotNull
#Size(min=1, max=50)
private String lastname;
#NotNull
#Email
#Column(unique=true)
private String email;
#ManyToMany(cascade= {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST, CascadeType.REFRESH}
, fetch= FetchType.LAZY)
#JoinTable(name="employee_project",
joinColumns=#JoinColumn(name="employee_id"),
inverseJoinColumns=#JoinColumn(name="project_id"))
#JsonIgnore
private List<Project> projects;
public List<Project> getProjects() {
return projects;
}
public void setProjects(List<Project> projects) {
this.projects = projects;
}
public Employee() {
super();
}
public Employee(String firstName, String lastname, String email) {
super();
this.firstName = firstName;
this.lastname = lastname;
this.email = email;
}
public long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(long employeeId) {
this.employeeId = employeeId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
you can see the post request I have tried in this picture link check it out
Post request from arch
so how can i use the POST,PUT,DELETE and PATCH request
As far as I know, HttpRequestMethodNotSupportedException occurs when your end point is identified but you are sending wrong REST action type. For example, you are sending request with POST which is actually a GET endpoint.
Also, I do not see any specific endpoint defined for POST/PUT/PATCH. Rest endpoints must be action verbs for e.g. baseURL/create -> To create a resource and so on..
I have a dropwizard service in which I am trying to implement request validation, and below is the code for same.
import com.google.common.collect.ImmutableMap;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/system-info")
#Produces(MediaType.APPLICATION_JSON)
public class SystemInfo {
#GET
#Path("/get")
public Response testValidation(#QueryParam("name") String name,
#QueryParam("phoneNo") Long phoneNo,
#QueryParam("email") String email,
#QueryParam("password") String password) {
if(email == null) {
return Response.ok(ImmutableMap.of("status", "email missing")).build();
}
//bunch of other validations
return Response.ok(ImmutableMap.of("status", "ok")).build();
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Path("/post")
public Response testPostValidation(final Person person) {
if(person.getEmail() == null) {
return Response.ok(ImmutableMap.of("status", "email missing")).build();
}
return Response.ok(ImmutableMap.of("status", "ok")).build();
}
}
class Person {
#JsonProperty
private String name;
#JsonProperty
private String email;
#JsonProperty
private long phoneNo;
#JsonProperty
private String password;
public String getEmail(){
return email;
}
public Person(){};
}
In both the GET and POST method I have the QueryParams and the Person object which I would like to be validated.
I have the validation logic inside the Resource class itself, I can create a separate class and replace the if statements with
//if(email == null) {
// return Response.ok(ImmutableMap.of("status", "email missing")).build();
//}
if(!CustomValidater.validate(email, name, phone, password)) {
return Response.ok(ImmutableMap.of("status", "data missing")).build();
}
and do the same for POST as well this way the validation logic is abstracted in different class.
Is this the correct way of doing the validation or should I create custom annotation that will do this validation?
You should create custom validator, or add constraints validation to model.
Person should have properties like:
#NotNull
private String name;
#NotEmpty
private String surname;
...
And should be validated as method parameter if needed:
#Valid Person person
I am trying to pass a person object to my test method below but i am getting an error when i try to run it in postman. Any help will be greatly appreciated
In postman, i used the following JSON in the body
{
"name" : "aasd",
"address" : "asd",
"age" : "asdads",
"sex" : "asdsad"
}
Person model
package com.test.model;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.math.BigDecimal;
import java.util.Date;
#XmlRootElement
public class Person{
#XmlElement
private String name;
#XmlElement
private String address;
public Person() {
}
public void setName(String name) {
this.name= name;
}
#XmlElement
public String getName() {
return name;
}
public void setAddress(String address) {
this.address= address;
}
#XmlElement
public String getAddress() {
return address;
}
}
Controller
package com.test2.controller;
import javax.annotation.security.PermitAll;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.test.model;
#Path("person")
public class PersonController {
#PermitAll
#POST
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
#Path("test")
public Person addPerson(Person person) {
return person;
}
}
Error Message
exception
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: Could not initialize class org.eclipse.persistence.jaxb.BeanValidationHelper
root cause
org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: Could not initialize class org.eclipse.persistence.jaxb.BeanValidationHelper
root cause
java.lang.NoClassDefFoundError: Could not initialize class org.eclipse.persistence.jaxb.BeanValidationHelper
I'm building a rest controller using Spring to handle request and Jackson to serialize data.However I followed tutorial online but I end up getting an error.
HTTP Status 406 -
type Status report
message
description The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
After Google for a while, I realized that it is because I don't have "application/json" as my "Accept" header in my request:
So I use a tool called Postman to manually add this "Accept" header in the request, send the request again, but still getting the same error:
I'm so confused, I've already included "application/json" as one of accepted data-type, why I still have this data-unsupported error? FYI, here is my Rest Controller class:
package mywebapp.controller;
import java.io.IOException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import mywebapp.dao.model.interfaces.PetDao;
import mywebapp.model.Pet;
#RestController
#RequestMapping(value = "petJson.htm")
public class PetControllerAjax {
private static final Logger LOG = LoggerFactory.getLogger(PetController.class);
public static Logger getLog() {
return LOG;
}
#Autowired
#Qualifier("PetDaoJpaImpl")
private PetDao petDao;
public PetDao getPetDao() {
return petDao;
}
public void setPetDao(PetDao petDao) {
this.petDao = petDao;
}
#RequestMapping(method = RequestMethod.GET)
public List<Pet> getAllPets() throws IOException {
getLog().info("Rest Controller activating........");
List<Pet> petList = getPetDao().getAllPets();
return petList;
}
}
And here is my Pet entity class:
package mywebapp.model;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Date;
import java.util.Set;
#Entity
#Table(name = "pet")
public class Pet {
private int petId;
private String name;
private String owner;
private String species;
private String sex;
private Date birth;
private Date death;
private Set<Toy> toys;
#Id
#Column(name = "pet_id")
#GeneratedValue
#JsonProperty(value="pet_id",required=true)
public int getId() {
return petId;
}
public void setId(int id) {
this.petId = id;
}
#JsonProperty(value="pet_name",required=true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Date getDeath() {
return death;
}
public void setDeath(Date death) {
this.death = death;
}
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER,targetEntity=Toy.class, mappedBy="pet")
public Set<Toy> getToys() {
return toys;
}
public void setToys(Set<Toy> toys) {
this.toys = toys;
}
}
Anyone knows what's going on here? Any hint will be appreciated, lots of thanks in advance!
Jackson 2.7 is not supported by Spring 4.2 - it will be in 4.3+.
Check out the library requirements for Spring on the Spring wiki and see SPR-13728 and SPR-13483.
package model;
import java.net.URI;
import java.util.Collection;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
#Path("/item")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Stateless
public class InfoRestService {
// the PersistenceContext annotation is a shortcut that hides the fact
// that, an entity manager is always obtained from an EntityManagerFactory.
// The peristitence.xml file defines persistence units which is supplied by
// name
// to the EntityManagerFactory, thus dictating settings and classes used by
// the
// entity manager
#PersistenceContext(unitName = "Task")
private EntityManager em;
// Inject UriInfo to build the uri used in the POST response
#Context
private UriInfo uriInfo;
#POST
public Response createItem(PersonInfo item) {
if (item == null) {
throw new BadRequestException();
}
em.persist(item);
// Build a uri with the Item id appended to the absolute path
// This is so the client gets the Item id and also has the path to the
// resource created
URI itemUri = uriInfo.getAbsolutePathBuilder().path(item.getId()).build();
// The created response will not have a body. The itemUri will be in the
// Header
return Response.created(itemUri).build();
}
#GET
#Path("{id}")
public Response getItem(#PathParam("id") String id) {
PersonInfo item = em.find(PersonInfo.class, id);
if (item == null) {
throw new NotFoundException();
}
return Response.ok(item).build();
}
// Response.ok() does not accept collections
// But we return a collection and JAX-RS will generate header 200 OK and
// will handle converting the collection to xml or json as the body
#GET
public Collection<PersonInfo> getItems() {
TypedQuery<PersonInfo> query = em.createNamedQuery("PersonInfo.findAll",
PersonInfo.class);
return query.getResultList();
}
#PUT
#Path("{id}")
public Response updateItem(PersonInfo item, #PathParam("id") String id) {
if (id == null) {
throw new BadRequestException();
}
// Ideally we should check the id is a valid UUID. Not implementing for
// now
item.setId(id);
em.merge(item);
return Response.ok().build();
}
#DELETE
#Path("{id}")
public Response deleteItem(#PathParam("id") String id) {
PersonInfo item = em.find(PersonInfo.class, id);
if (item == null) {
throw new NotFoundException();
}
em.remove(item);
return Response.noContent().build();
}
}
package model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
/**
* The persistent class for the person_info database table.
*
*/
#Entity
#XmlRootElement
#Table(name="person_info")
#NamedQuery(name="PersonInfo.findAll", query="SELECT p FROM PersonInfo p")
public class PersonInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String id;
private String email;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
public PersonInfo() {
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
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;
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="Task">
<jta-data-source>jdbc/DBtest</jta-data-source>
<class>model.PersonInfo</class>
</persistence-unit>
</persistence>
and the other class is Application
package model;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("rest")
public class ApplicationConfig extends Application{
}
I really have no idea, the connections are made ok .. I'm using Glassfish 4 server and MySQL database... code is deploying but when I want to access the localhost:8080/Task/.. (my app) the only thing it says is this:
"HTTP Status 404 - Not Found / Type Status report
messageNot Found
descriptionThe requested resource is not available."
The code you supplied is working (when commenting out the persistence related stuff), I guess you are just confusing something.
The #ApplicationPath annotation sets the root context which comes after your project name.
If you project name really is Task you have to use this URL: http://localhost:8080/Task/rest/item
Otherwise: http://localhost:8080/YOUR_PROJECT_NAME/rest/item
See also:
How to set up JAX-RS Application using annotations only (no web.xml)?