I have a very weird problem with Jersey REST services. I'm using:
Glassfish
sh4.0
EJB3.1
JDK1.7
Netbeans8.0
When I persist an object by GET request it normally store in database:
#Singleton
#Path("/person")
public class SampleRest {
#EJB
PersonFasade personFasade;
#GET
public Person getPerson1(
final #QueryParam("id") String id,
final #QueryParam("first") String first,
final #QueryParam("last") String last)
{
final Person person = this.personFasade.create(id, first, last);
return person;
}
}
But when I'm using POST:
...
#POST
public Person getPerson3(Person person) {
this.personFasade.create(person);
return person;
}
...
Everything works but Object does not store in database (without any error)!!
I'm pretty sure that is the parameter, you should use the #Consumes annotation to pass a Person object as JSON/XML parameter or use the same #QueryParam annotations to describe the object to persist.
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Person getPerson3(Person person) {
this.personFasade.create(person);
return person;
}
I found the problem! It was because I forgot to put beans.xml into WEB-INF folder!!! I don't know how it is possible to such things happen by this mistake!! After I did it works. I switch to Wildfly, seems it's more stable, with very good useful logs and error message.
Related
I am experimenting with the library OmniPersistence.
I have a problem using the class org.omnifaces.persistence.model.VersionedEntity. In my code there is a simple entity class City.
#Entity
public class City extends VersionedEntity<Long> {
#Id
#GeneratedValue
private Long id;
private String postalCode;
private String name;
... (getter + setter)
}
There is a REST-Service that exposes the Entity for some client-applications. But every time I want to update an object a javax.persistence.OptimisticLockException is thrown. The problem is that the version attribute is always null. A look in the code of VersionedEntity revealed that there is no setter method, but a comment
// No setter! JPA takes care of this.
I do understand the intention of the absence of the setter method but that is the reason for the exception.
Question
Is my architecture so poor (exposing the entity class in a web-service) or is it maybe reasonable to add a setter method although JPA should handle the value/manipulation of the #Versioned attribute?
Edit (as requested by the comment)
My update method is basically the one in OmniPersistence' BaseEntityService. My service class looks like the following.
#Stateless
public class CityService extends BaseEntityService<Long, City> {
public Long count() {
return super.createLongQuery("select count(c) from City c").getSingleResult();
}
}
My controller is the REST endpoint.
#Path("city")
public class CityEndpoint {
#Inject
private CityService cityService;
#GET #Produces(MediaType.APPLICATION_JSON)
public Response getAll() {
List<City> cities = cityService.list();
return Response.ok(cities).build();
}
#GET #Produces(MediaType.APPLICATION_JSON)
#Path("{id}")
public Response get(#PathParam("id") Long id) {
return Response.ok(cityService.getById(id)).build();
}
#POST #Consumes(MediaType.APPLICATION_JSON)
public Response create(City city) {
cityService.persist(city);
return Response.created(URI.create(String.format("city/%s", Objects.toString(city.getId())))).build();
}
#POST #Consumes(MediaType.APPLICATION_JSON)
#Path("update")
public Response update(City city) {
System.out.println(city);
City updated = cityService.update(city);
return Response.ok(updated).build();
}
#GET
#Path("count")
public Response count() {
return Response.ok(cityService.count()).build();
}
}
The JPA specification document provides an important hint that you must not manipulate the #Version attribute, see section 3.4.2, on page 90
An entity may access the state of its version field or property or
export a method for use by the application to access the version,
but must not modify the version value.
and
The version attribute is updated by the persistence provider runtime
when the object is written to the database.
So the comment (”No setter! JPA takes care of this.“) you find in VersionedEntity is absolutely reasonable. In essence, you should not change (or null) the #Version attribute from higher application levels.
In your case, it seems, you must compensate the ”lost“ (=nulled) version effect, eg by introducing a DTO for City. Otherwise, you will always run into an OptimisticLockException.
So far in my Java code with Spring Boot I was using models, or POJO objects to achieve better control of my objects, etc. Usually I am creating Entities, Repositories, Services, Rest controllers, just like documentation and courses are suggesting.
Now however I am working with Thymeleaf templates, HTML a bit of Bootstrap and CSS in order to create browser interface. For methods in #Controller, as parameter, I am passing Model from Spring Model UI like this:
#GetMapping("/employees")
private String viewAllEmployees(Model employeeModel) {
employeeModel.addAttribute("listEmployees", employeeService.getAllEmployees());
return "employeeList";
}
My question is: How can I use my POJO objects instead of org.springframework.ui.Model;?
My first guess was this:
public class EmployeeModel implements Model{
private long employeeId;
private String firstName;
private String lastName;
private String email;
private String phone;
private long companyId;
//getter and setter methods
}
And in order to do that I have to #Override Model methods which is fine with me. And it looks like Java, Spring etc. does not complain in compile time, and I can use this POJO object in my #Controller like this:
#Controller
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/employees")
private String viewAllEmployees(EmployeeModel employeeModel) {
employeeModel.addAttribute("listEmployees", employeeService.getAllEmployees());
return "employeeList";
}}
I run the code and it starts, shows my /home endpoint which works cool, however when I want to go to my /employees endpoing where it should show my eployees list it throws this:
Method [private java.lang.String com.bojan.thyme.thymeApp.controller.EmployeeController.viewAllEmployees(com.bojan.thyme.thymeApp.model.EmployeeModel)] with argument values:[0] [type=org.springframework.validation.support.BindingAwareModelMap] [value={}] ] with root cause java.lang.IllegalArgumentException: argument type mismatch
exception.
Please note that Rest controller is working perfectly in browser and Postman.
Is it possible that String as a method is the problem? Should my method be of some other type like List<EmployeeModel> or maybe EmployeeModel itself? If it is so, how to tell the method that I want my employeeList.html to be returned?
I sincerely hope that someone can halp me with this one :)
How can I use my POJO objects instead of org.springframework.ui.Model;?
I don't think that is the best practice when you are working with Thymeleaf. According to their documentation, you should attach your Objects to your Model. So in your controller you would be manipulating models that contain your Pojos.
Example:
#RequestMapping(value = "message", method = RequestMethod.GET)
public ModelAndView messages() {
ModelAndView mav = new ModelAndView("message/list");
mav.addObject("messages", messageRepository.findAll());
return mav;
}
You should always use org.springframework.ui.Model as argument. This class is basically a Map with key/value pairs that are made available to Thymeleaf for rendering.
Your first example is how you should do it:
#GetMapping("/employees") //<1>
private String viewAllEmployees(Model model) {
model.addAttribute("employees", employeeService.getAllEmployees()); // <2>
return "employeeList"; // <3>
}
<1> This is the URL that the view will be rendered on
<2> Add any Java object you want as attribute(s) to the model
<3> Return the name of the Thymeleaf template. In a default Spring Boot with Thymeleaf application, this will refer to the template at src/main/resources/templates/employeeList.html. In that template, you will be able to access your model value with ${employees}.
I am writing Jersey RESTful web services. All my method like add, delete, get work. But i want create method who showing what book what user borrowing.
public class UserManagement {
private Map<Long, UserMaker> userMaker = DataBase.getUserMaker();
public UserManagement(){ //id , name, surname, nin, status of book
userMaker.put((long) 1, new UserMaker(1,"John", "Castles", 12345,0));
public UserMaker hireBook(UserMaker user, BookMaker book){ // method who update status hiring book , if 0 that means book is rented
if(user.getId() <= 0){
return null;
}
book.setStatus((int) user.getId()); //
user.setWhatIhave((int) (book.getId())); // convert int to long
userMaker.put(user.getId(), user);
return user;
} }
And now i want using method with multiple parameters
#Path("/user")
public class UserCRUD {
UserManagement userManagementWS = new UserManagement();
#PUT
#Path("/{idU}/{idB}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public UserMaker hireBook(
#PathParam("idU") long idU, UserMaker user,
#PathParam("idB") long idB, BookMaker book) {
user.setId(idU);
return userManagementWS.hireBook(user, book); //borrowing books
} }
And i got error, but all looks fine:
Method public project.emil.lib.model.UserMaker project.emil.lib.resources.UserCRUD.hireBook(long,project.emil.lib.model.UserMaker,long,project.emil.lib.model.BookMaker) on resource class project.emil.lib.resources.UserCRUD contains multiple parameters with no annotation. Unable to resolve the injection source.
Any tip? :)
Resource methods may not have more than one entity parameter. You can have multiple #PathParam, #QueryParam, etc. but only one unannotated parameter in each resource method.
3.3.2.1 Entity Parameters
The value of a parameter not annotated with
#FormParam
or any of the annotations listed in in Section 3.2,
called the entity parameter, is mapped from the request entity body. Conversion between an entity body and
a Java type is the responsibility of an entity provider, see Section 4.2. Resource methods MUST have at
most one entity parameter.
http://download.oracle.com/otn-pub/jcp/jaxrs-2_1-final-eval-spec/jaxrs-2_1-final-spec.pdf
You could remove UserMaker user from your resource method and instead pass the user id to userManagementWS.hireBook(idU, book). And then retrieve the user from your Map<Long, UserMaker> via userMaker.get(idU).
https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#get-java.lang.Object-
But I'd recommend you restructure your api. I found this link pretty informative http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api.
I am using spring boot, spring web and spring data for the following example.
I have one entity called Person and I already populated two Persons in the database:
Person entity
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false)
private long id;
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Personne() {
}
public Personne(long id, String name) {
this.id = id;
this.name = name;
}}
PersonRepository
#Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}
PersonController
#RestController
public class PersonController {
#Autowired
private PersonRepository personRepo;
#RequestMapping(value = "/perss/{id}")
public Person getById(#PathVariable("id") long id) {
return personRepo.xxxx(id);
}}
Use case 1:
When I replace personRepo.xxxx(id) with personRepo.getOne(id) and tap localhost:8080/perss/1 i get Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) error in the browser due to the fact that getOne() method returns a proxy to Person that jackson somehow cannot convert.
Use case 2:
When I replace personRepo.xxxx(id) with personRepo.findOne(id) and tap localhost:8080/perss/1 I get the desired Person object in the correct JSON format (this one works fine).
Use case 3:
When I replace PersonController getById() method's code with the following one:
#RequestMapping(value = "/perss/{id}")
public Person getById(#PathVariable("id") long id) {
Person p1 = personRepo.findOne(id);
Person p2 = personRepo.getOne(id);
return p2;
}
And tap localhost:8080/perss/1 I get the wanted Person object in the correct JSON format.
Question:
Using getOne() got me an error, but using findOne() and getOne() together gave me good result.
How does the findOne() influence the getOne()'s behavior.
EDIT
Use Case 4
When I reverse the order of p1 and p2 i get an error.
#RequestMapping(value = "/perss/{id}")
public Person getById(#PathVariable("id") long id) {
Person p2 = personRepo.getOne(id);
Person p1 = personRepo.findOne(id);
return p2;
}
Try to return p1 and you probably get the same error.
#RequestMapping(value = "/perss/{id}")
public Person getById(#PathVariable("id") long id) {
Person p1 = personRepo.findOne(id);
Person p2 = personRepo.getOne(id);
return p1;
}
You didn't get any, because you didn't serialized p1 which is JavassistLazyInitializer proxy. You serialized p2 instead which was already fine.
This one also will be fine:
#RequestMapping(value = "/check/{id}")
public void getById(#PathVariable("id") long id) {
personRepo.getOne(id);
}
JSON-serialization occurs when the object converted to from POJO to JSON.
The error with serialization of beans that have lazy-init properties occurs because serialization happens before their full loading.
You can try to fix the error with findOne() doing the following options:
Set the property below to your application.properties file (as exception message suggests):
spring.jackson.serialization.fail-on-empty-beans=false
Annotate entity with lazy-init properties like:
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
So, answering the question:
How does the findOne() influence the getOne()'s behavior.
It doesn't. And also calls to repositories doesn't invoke JSON serialization process.
You are correct that the order of invocation does effect the result when using both findOne() and getOne().
Short Answer: Both methods will first lookup the ID in the persistence context and return the cached value if it is present. If there is nothing found in the persistence context, they will proceed to load their preferred result and cache it. The cached value will be found by the other method the next time it runs.
getOne(id) will load (and cache) a proxy if id is not in the persistence context.
findOne(id) will load (and cache) the naked entity if id is not in the persistence context.
Long Answer: I ran into the same problem and my project uses Hibernate 5.2.4.Final. The details of what is happening involves some Hibernate code. After debugging for a while I found that both findOne() and getOne() eventually call Hibernate's DefaultLoadEventListener.onLoad() method, but they call it with different loadType arguments:
getOne() eventually delegates to SessionImpl.IdentifierLoadAccessImpl<T>.doGetReference() which specifies the loadType of LoadEventListener.LOAD which is eventually passed down to DefaultLoadEventListener.proxyOrLoad(). LoadEventListener.LOAD does allow for the creation of a proxy.
findOne() eventually delegates to SessionImpl.IdentifierLoadAccessImpl<T>.doLoad() which specifies the loadType value of LoadEventListener.GET which is eventually passed down to DefaultLoadEventListener.proxyOrLoad(). LoadEventListener.GET does not allow creation of a proxy.
Set a breakpoint in DefaultLoadEventListener.proxyOrLoad() to verify that the LoadType options argument that is passed in has different values for its allowProxyCreation field depending on whether findOne() or getOne() is calling it.
You can see that if allowProxyCreation is true and there is no proxy, then proxyOrLoad() will return the result of createProxyIfNecessary(). In the case where only getOne() is used, this will result in returning a proxy.
If it happens that findOne() was called for the same entity type and ID before getOne(), then when the getOne() call makes its way into createProxyIfNecessary() it will return early because the entity will already be found in the persistence context. In that case calling getOne() will not result in creating a proxy.
If you call getOne() before findOne() then the proxy will be created and stored in the persistence context, and findOne() will also return the proxy because it will simply retrieve the cached proxy from the persistence context.
I have a scenario where a property has a different validation applied depending on end-point. This is done via "groups" (code example below & reference to dropwizard doc: http://www.dropwizard.io/0.9.3/docs/manual/validation.html#validated).
I implemented the DropWizard validations but the Swagger does not recognizing the "groups" and therefore doesn't provided correct model description. In addition Swagger doesn't seem to have any annotations that would accomplish the scenario.
Can you please help?
Thank you.
public interface Version1FirstName { }
public interface Version2FirstName { }
class Person {
#NotEmpty(groups = Version1FirstName .class)
#Length(max = 5, groups = Version2FirstName .class)
private firstName;
private lastName;
}
#POST
#Path("/v1")
public void addName(#Validated(Version1FirstName.class) Person person) {}
#POST
#Path("/v2")
public void retriveName(#Validated({Version2FirstName.class,
Version1FirstName.class}) Person person) {}