I created one spring data jpa Application. In this application my method request is GET. but if I am trying to access that method Request url as post request. In this situation I want to know how to add HTTP status code 405(Method Not Allowed) with my custom error message.
Here is my code snippet
DepartmentModel
package com.demo.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "department")
public class DepartmentModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
public Integer ndeptid;
public String sdeptname ;
public Integer ninstid ;
public Boolean bislocked;
public String sclientdeptid;
public Integer nsurveymethodid;
public Boolean bisjointuse;
public Integer ntempdeptid;
public Boolean balternatejointusepercentage;
public Integer ndivid;
//getter and setter
DepartmentRepository
#Repository
public interface DepaertmentRepository extends JpaRepository<DepartmentModel, Integer>
{
#Query("select new map(dep.sdeptname as sdeptname)"
+ " from DepartmentModel as dep where dep.ninstid=60")
Set<DepartmentModel> findBySDepName();
}
DepartmentService
#Service
public class DepartmentService
{
#Autowired
DepaertmentRepository depRepo;
public Set<DepartmentModel> findDepName()
{
return depRepo.findBySDepName();
}
}
DepartmentController
#RestController
#RequestMapping("/SpaceStudy/SpaceAdmin")
public class DepartmentController {
#Autowired
DepartmentService depService;
#CrossOrigin(origins="*")
#GetMapping("AccountMaintenance/LoadDepartment")
//#ResponseStatus( value = HttpStatus.METHOD_NOT_ALLOWED)
public Set<DepartmentModel> findDepName() {
return depService.findDepName();
}
}
can any one help me how to add HTTP status code (405) with proper message when i am accessing GET request as post
You can override the method handleHttpRequestMethodNotSupported of ResponseEntityExceptionHandler and implement your own error message object. For example:
#Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest req) {
headers.setAllow(ex.getSupportedHttpMethods());
ErrorMessage errorMessage = ErrorMessage.of(
status.value(),
"You cannot make this request - the method is not allowed!",
ex.getMessage(),
((ServletWebRequest) req).getRequest().getServletPath()
);
return new ResponseEntity<>(errorMessage, headers, status);
}
#Value(staticConstructor = "of")
private static class ErrorMessage {
private Instant timestamp = Instant.now();
private Integer status;
private String error;
private String message;
private String path;
}
See my full demo for more info.
You can override not only this method of ResponseEntityExceptionHandler but all the remaining to get custom handling of other exceptions.
Note: you can use another approach to handle exceptions (or use both) - implement an exception handler.
UPDATE
It's necessary to add #ControllerAdvice annotation to the class that extended ResponseEntityExceptionHandler.
Related
import javax.ws.rs.FormParam;
import com.alibaba.fastjson.JSON;
Hi guys, The JAX-RS seems cannot init the list field in resteasy 2.x/3.x/4.x automatically,
Here is my VO used in servce
public class OrderVO {
#FormParam("id")
private long id;
#FormParam("title")
private String title;
#FormParam("product")
private List<Integer> product;
...
public String toString() {
return JSON.toJSONString(this);
}
}
And here is my service method:
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED+";charset=UTF-8")
#Path("/create")
public InsertResult saveOrder(#BeanParam OrderVO order) {
logger.debug(order.toString());
}
Other parameters are auto inited except the List or Integer[], and can anyone tell me why....
I am tasked with creating a simple web api using JAVA EE and I cant use other external frameworks such as Spring Boot.
I got the get requests to work that was simple, however when I try to return a JSON to the api all I see is {} in postman or browser even though I created a user.
here is my current code
package ab.service;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
#Path("/MyRestService")
#ApplicationPath("resources")
public class RestService extends Application {
// http://localhosts:8080/BankTaskV1/ressources/MyRestService/sayHello
#GET
#Path("/sayHello")
public String getHelloMsg() {
return "Hello World";
}
#GET
#Path("/echo")
public Response getEchoMsg(#QueryParam("message") String msg) {
return Response.ok("you message was: " + msg).build();
}
#GET
#Path("/User")
public Response getUser() {
// Gson gson = new Gson();
User user = new User(1, "Ahmad");
return Response.status(Response.Status.OK).entity(user).type(MediaType.APPLICATION_JSON).build();
// return gson.toJson(user);
}
#POST
#Path("/CreateUser")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public void createUser(UserRequest requestBody) {
System.out.println("create ran");
System.out.println(requestBody.UserName);
}
}
as you can see in the User endpoint I used GSON to convert user object to a json string and that worked, however I read online that it should work without it if I did it by returning an entity, something called POJO?
but that just gives me an empty {}
furthermore in the endpoint CreateUser I set it to consume json and gave it a request body with class that i defined. but when I try to print the username it gives me null, andd the create ran system output shows that the function ran.
here is my User class
package ab.service;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class User {
private int id;
private String name;
public User() {
}
public User(int id, String name) {
super();
this.id = id;
this.name = name;
}
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
int getId() {
return id;
}
void setId(int id) {
this.id = id;
}
}
and my userrequest class
package ab.service;
import javax.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
#XmlRootElement
public class UserRequest {
#XmlElement
String UserName;
#XmlElement
int Id;
}
I'm trying to implement domain event publishing from an entity by following the examples mentioned on the post below:
Example for #DomainEvents and #AfterDomainEventsPublication
However I haven't managed to have Spring calling my method annotated with #TransactionalEventListener.
See below the entity, service, event listener and test code:
#Entity
public class Book extends AbstractAggregateRoot<Book>
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(unique = true)
private String isbn;
#Column
private String name;
public Book(String isbn, String name)
{
this.isbn = isbn;
this.name = name;
}
public void purchase()
{
registerEvent(new BookPurchasedEvent(id));
}
// getters omitted for brevity
}
Service:
#Service
#Transactional
public class BookService
{
private final BookRepository bookRepository;
public BookService(BookRepository bookRepository)
{
this.bookRepository = bookRepository;
}
public void purchaseBook(Integer bookId)
{
Book book = bookRepository.findById(bookId)
.orElseThrow(NoSuchElementException::new);
book.purchase();
bookRepository.save(book);
}
}
Listener:
#Service
public class EventListener
{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#TransactionalEventListener
public void handleEvent(BookPurchasedEvent event)
{
logger.info("Received event {}", event);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#Transactional
public class BookEventsTest
{
#Autowired
private BookService bookService;
#Autowired
private EntityManager entityManager;
#Test
public void test()
{
Book book = new Book("abcd-efgh", "El Quijote");
book = entityManager.merge(book);
bookService.purchaseBook(book.getId());
}
}
The log message from the listener is not logged. It works though when deployed as a REST service and invoked e.g. via Postman
Got it. Since my test is annotated with #Transactional, the transaction wrapping the test method will be rolled back. Therefore the method annotated with #TransactionalEventListener won't be called, since by default it triggers at the phase TransactionPhase.AFTER_COMMIT (and I'm not interested in having it called unless the transaction is successful). So the working version of the test looks as follows:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BookEventsTest
{
#Autowired
private BookService bookService;
#Autowired
private BookRepository bookRepository;
#MockBean
private EventListener eventListener;
private Book book;
#Before
public void init() {
book = bookRepository.save(new Book("abcd-efgh", "El Quijote"));
}
#After
public void clean() {
bookRepository.deleteAll();
}
#Test
public void testService()
{
bookService.purchaseBook(book.getId());
then(eventListener)
.should()
.handleEvent(any(BookPurchasedEvent.class));
}
}
In the REST endpoint I'm building in Spring Boot, I'm trying to pass my vehicleDTO to my controller. But before it reaches my controller, there is an error.
InvalidDefinitionException: Cannot construct instance of
com.vehicle.datatransferobject.VehicleDTO (no Creators, like default
construct, exist): cannot deserialize from Object value (no delegate-
or property-based Creator)
vehicleDTO
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.myvehicle.EngineType;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class VehicleDTO {
#JsonIgnore
private Long id;
#NotNull(message = "vehiclenumber can not be null!")
private String vehiclenumber;
#Min(2)
#NotNull(message = "Seat count can not be less than 2!")
private Integer vehicleseatcount;
#NotNull(message = "Engine Type can not be null!")
private EngineType enginetype;
#Max(5)
private Integer vehiclerating;
private VehicleDTO(Long id, String vehiclenumber, Integer vehicleseatcount, EngineType enginetype,Integer vehiclerating){
this.vehiclenumber=vehiclenumber;
this.vehicleseatcount=vehicleseatcount;
this.enginetype=enginetype;
this.vehiclerating=vehiclerating;
this.id=id;
}
public static VehicleDTOBuilder newBuilder()
{
return new VehicleDTOBuilder();
}
#JsonProperty
public Long getId() {
return id;
}
public String getvehiclenumber() {
return vehiclenumber;
}
public Integer getvehicleseatcount() {
return vehicleseatcount;
}
public EngineType getEnginetype() {
return enginetype;
}
public Integer getvehiclerating() {
return vehiclerating;
}
public static class VehicleDTOBuilder{
private Long id;
private String vehiclenumber;
private Integer vehicleseatcount;
private EngineType enginetype;
private Integer vehiclerating;
public VehicleDTOBuilder setId(Long id) {
this.id = id;
return this;
}
public VehicleDTOBuilder setvehiclenumber(String vehiclenumber) {
this.vehiclenumber = vehiclenumber;
return this;
}
public VehicleDTOBuilder setvehicleseatcount(Integer vehicleseatcount) {
this.vehicleseatcount = vehicleseatcount;
return this;
}
public VehicleDTOBuilder setEnginetype(EngineType enginetype) {
this.enginetype = enginetype;
return this;
}
public VehicleDTOBuilder setvehiclerating(Integer vehiclerating) {
this.vehiclerating = vehiclerating;
return this;
}
public VehicleDTO createVehicleDTO()
{
return new VehicleDTO(id, vehiclenumber, vehicleseatcount, enginetype,vehiclerating);
}
}
}
My DTO has an Enum type called EngineType
public enum EngineType {
ELECTRIC, DIESEL
}
My controller looks like this
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public VehicleDTO addvehicle(#Valid #RequestBody VehicleDTO vehicleDTO)
{
VehicleDO vehicleDO = Mapper.VehicleDO(vehicleDTO);
return Mapper.makeVehicleDTO(Service.addvehicle(vehicleDO));
}
This exception :
InvalidDefinitionException: Cannot construct instance of
com.vehicle.datatransferobject.VehicleDTO (no Creators, like default
construct, exist): cannot deserialize from Object value (no delegate-
or property-based Creator)
means that Jackson didn't find a way to instantiate VehicleDTO that is the default constructor (no arg constructor) or a JsonCreator.
As you use a builder pattern you will configure the VehicleDTO class to make Jackson to instantiate VehicleDTO with the VehicleDTOBuilder such as :
#JsonDeserialize(builder = VehicleDTO.VehicleDTOBuilder.class)
public class VehicleDTO {
...
}
And annotate your builder with JsonPOJOBuilder as :
#JsonPOJOBuilder(buildMethodName = "createVehicleDTO", withPrefix = "set")
public static class VehicleDTOBuilder{
...
}
According to the javadoc, JsonPOJOBuilder is :
used to configure details of a Builder class: instances of which are
used as Builders for deserialized POJO values, instead of POJOs being
instantiated using constructors or factory methods. Note that this
annotation is NOT used to define what is the Builder class for a POJO:
rather, this is determined by JsonDeserialize.builder() property of
JsonDeserialize.
I faced this error when I used Lombok's #Builder and #Data annotations together on a POJO class that is used for connecting to an API (either for consuming or for providing response)
I removed the #Builder annotation and then it is working fine
In my case:
InvalidDefinitionException: Cannot construct instance of com.vehicle.datatransferobject.VehicleDTO (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
for the above exception, I just write Default Constructor which instantiates class and solved the problem.
Default Constructor:
public VehicleDTO() {
super();
// TODO Auto-generated constructor stub
}
If you are using Lombok - the best thing is to add these annotations to your DTO:
#AllArgsConstructor
#RequiredArgsConstructor
#Data
#Builder (optional)
In addition to davidxxx`s answer. I used Lombok. And in my case it looked like this:
#Data
#JsonDeserialize(builder = SomeClass.SomeClassBuilder.class)
#Builder(builderClassName = "SomeClassBuilder")
public class SomeClass {
// ...
#JsonPOJOBuilder(withPrefix = "")
public static class SomeClassBuilder {
}
}
I've been through a few documentations, but am not able to communicate to the datastore yet...can anyone give me a sample project/code of objectify used in GWT web app(I use eclipse)...just a simple 'put' and 'get' action using RPC should do...or, atleast tell me how its done
Easiest way to understand how to make objectify work is to repeat all steps described in this article from David's Chandler blog. Whole blog is a pretty much must read if you interested in GWT, GAE(Java), gwt-presenter, gin\guice,etc. There you will find working example, but anyway here i'll show a slighly advanced example.
In package shared define your entity/model:
import javax.persistence.Embedded;
import javax.persistence.Id;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Unindexed;
#Entity
public class MyEntry implements IsSerializable {
// Objectify auto-generates Long IDs just like JDO / JPA
#Id private Long id;
#Unindexed private String text = "";
#Embedded private Time start;
// empty constructor for serialization
public MyEntry () {
}
public MyEntry (Time start, String text) {
super();
this.text = tText;
this.start = start;
}
/*constructors,getters,setters...*/
}
Time class (also shared package) contains just one field msecs:
#Entity
public class Time implements IsSerializable, Comparable<Time> {
protected int msecs = -1;
//rest of code like in MyEntry
}
Copy class ObjectifyDao from link above to your server.dao package. And then make DAO class specifically for MyEntry -- MyEntryDAO:
package com.myapp.server.dao;
import java.util.logging.Logger;
import com.googlecode.objectify.ObjectifyService;
import com.myapp.shared.MyEntryDao;
public class MyEntryDao extends ObjectifyDao<MyEntry>
{
private static final Logger LOG = Logger.getLogger(MyEntryDao.class.getName());
static
{
ObjectifyService.register(MyEntry.class);
}
public MyEntryDao()
{
super(MyEntry.class);
}
}
Finally we can make requests to database(server package):
public class FinallyDownloadingEntriesServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/plain");
//more code...
resp.setHeader("Content-Disposition", "attachment; filename=\""+"MyFileName"+".txt\";");
try {
MyEntryDao = new MyEntryDao();
/*query to get all MyEntries from datastore sorted by start Time*/
ArrayList<MyEntry> entries = (ArrayList<MyEntry>) dao.ofy().query(MyEntry.class).order("start.msecs").list();
PrintWriter out = resp.getWriter();
int i = 0;
for (MyEntry entry : entries) {
++i;
out.println(i);
out.println(entry.getStart() + entry.getText());
out.println();
}
} finally {
//catching exceptions
}
}