Update Web Service using REST API in Spring Hibernate - java

I am working with API's and I have to make the update web service. I have tried many ways but I am unable to fetch the desired result.
My domain class is;
#Entity
#Table(name="package")
public class Package{
private Integer packageId;
private String packageName;
private String description;
private Date validFrom;
private Date validUpto;
public enum Status{Active,Inactive}
private Status status;
#JsonBackReference
private Set<HospitalInformation> hospitalInformation=new HashSet<HospitalInformation>();
//getters and setters
My Dao Layer is
#Override
#Transactional(propagation=Propagation.REQUIRED)
public boolean updatePackage(Integer packageId,String packageName,String description,Date validFrom,Date validUpto, Status status) throws Exception {
Session session=sessionFactory.openSession();
Transaction tx= session.beginTransaction();
Package packages=hospitalDao.findByPackageId(packageId);
if(packages!=null){
packages.setPackageName(packageName);
packages.setDescription(description);
packages.setValidFrom(validFrom);
packages.setValidUpto(validUpto);
packages.setStatus(status);
session.saveOrUpdate(packages);
return true;
}else{
return false;
}
My service layer is
#Override
public boolean updatePackageInfo(Integer packageId,String packageName,String description,Date validFrom,Date validUpto, Status status) throws Exception {
return updateDao.updatePackage(packageId, packageName, description, validFrom, validUpto, status);
}
My Controller class has compilation errors:
#Controller
#RequestMapping("/update")
public class UpdateRecordController {
#Autowired
private UpdateService updateService;
static final Logger logger=Logger.getLogger(RestController.class);
#RequestMapping(value="/package", method= RequestMethod.PUT,consumes=MediaType.APPLICATION_JSON_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody Status updatePackageIfo( #RequestParam("Id") Integer Id){
Package packages=new Package();
try{
if(updateService.updatePackageInfo(Id)); //Error {
return new Status(1,"Successfylly Updated with Package Id "+packages.getPackageId());
}else{
return new Status(0,"Failed. Enter a valid packageId");
}
}catch(Exception e){
e.printStackTrace();
return new Status(0,e.getMessage());
}
}
}
Having checked all the links regarding Update Web Service, I couldn't find anything useful on Google. So i need solution of how to make Update Web service.

Related

Spring Boot server error while POST with Retrofit2, only happens when there are relationships in the database

I POST some data with Retrofit2 to a Spring Boot REST service and there are a lot of exceptions occurring in the server. This happens when I have relations in my database.
I have a REST service over a Spring Boot application that runs over the Heroku services, I was doing a login and a register tasks with an Android application, I am using Retrofit2 in Android to POST the data to the REST service, everything was working well until for some other reasons I create a relationship between users in my database, this relationship is a "follow", this is, create a relationship in a follow table where I have the ID of the user that is following and an ID of the user that is followed. When I create this relationship into the database and I try to login with the method that I created, I got a bunch of errors into the REST service that I do not know why is this happening.
So in Android I have the call of my Retrofit2 client and a method that creates the service passing as a parameter the UserService.class with the HTTP methods. I also pass as a parameter the user of the class User where have the information that I want to POST, then I call the enqueue method.
RetrofitClient.createService(UserService.class).login(user).enqueue(new CallBack<User>(){
#Override
public void onResponse(Call<User> call, Response<User> response) {
//Some logic here
}
});
Into my UserService.java I have the method that POST the user object information.
public interface UserService {
#POST("login")
public Call<User> login(#Body User user);
}
Now in the backend side I have a REST controller where I have the login endpoint that will be consumed for Retrofit2.
#PostMapping(path = "login", consumes = "application/json", produces = "application/json")
#CrossOrigin(origins = "*", methods= {RequestMethod.GET,RequestMethod.POST})
public Object login(#RequestBody String json) {
//Some logic here
}
As I said this endpoint runs fine when there are no relationships over a user into the DB, but when a user follow another one, this is, when there is a new row into the follow table, lets say:
follow table:
id_follow id_user_follower id_user_following
1 1 2
At the example above the user 1 follows the user 2, and when I try to login, this is, use the login method in the UserService class it throws me a bunch of errors.
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
And this repeat over 300 lines of errors.
The thing here is that between the bunch of error the server return a 200 HTTP response, I managed the exceptions in Spring Boot and I catch that, when I catch I send a code for an error to my Android Retrofit2 client, but the login does not work.
Expected result:
After sending the POST from Retrofit2 to Spring Boot the response have to be a HTTP 200 response but no exceptions have to happen into the server.
Actual result:
There is a 200 HTTP response from the server but there are a lot of exceptions into the server that return an error code to the Android application and the login does not work.
This is the entity that I want to return as JSON from the RestController in Spring Boot.
#Entity
#Table(name = "users")
public class User extends AuditModel{
private static final long serialVersionUID = 1700575815607801150L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idUser;
private String name;
private String lastName;
#Column(name = "nick_name", unique = true)
private String nickName;
private String avatarResource;
#Column(unique=true)
private String email;
private String password;
private String birthDate;
private String gender;
private String postalCode;
private int active;
public Long getIdUser() {
return idUser;
}
public void setIdUser(Long idUser) {
this.idUser = idUser;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getAvatarResource() {
return avatarResource;
}
public void setAvatarResource(String avatarResource) {
this.avatarResource = avatarResource;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBirthDate() {
return birthDate;
}
public void setBirthDate(String birthDate) {
this.birthDate = birthDate;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public Long getId() {
return idUser;
}
public void setId(Long idUser) {
this.idUser = idUser;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
/* Relations */
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Comment> comments;
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<UserMemory> userMemories;
public List<UserMemory> getUserMemories() {
return userMemories;
}
public void setUserMemories(List<UserMemory> userMemories) {
this.userMemories = userMemories;
}
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Vote> votes;
public List<Vote> getVotes() {
return votes;
}
public void setVotes(List<Vote> votes) {
this.votes = votes;
}
#OneToMany(mappedBy = "userFollower", fetch = FetchType.LAZY)
private List<Follow> usersFollowers;
public List<Follow> getUsersFollowers() {
return usersFollowers;
}
public void setUsersFollowers(List<Follow> usersFollowers) {
this.usersFollowers = usersFollowers;
}
#OneToMany(mappedBy = "userFollowing", fetch = FetchType.LAZY)
private List<Follow> usersFollowing;
public List<Follow> getUsersFollowing() {
return usersFollowing;
}
public void setUsersFollowing(List<Follow> usersFollowing) {
this.usersFollowing = usersFollowing;
}
}
By having fetchtype.LAZY, some of the values won't exist during serialization. This will make the ObjectMapper to try to fetch these and it all will end up in some kind of infinite loop.
It is never recommended to serialize #Entity annotated classes because database tables can change and that in turn will change the API for the calling clients.
Best way is to have specific ResponseDTOs that you transfer your data to before serialization so that the API and the database tables can change without breaking anything.
So, the problem was that in the backend I was using the writeValueAsString of the ObjectMapper class like this.
public Object register(#RequestBody String json){
User user = new User();
user.set...
...
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(user);
}
For some reason the writeValueAsString method gives a StackOverFlowException for a recursive behavior when there is a relationship into the database, this is a problem related with JPA or Hibernate, I am not sure about which one of those.
The solution was to write my own method to build a JSONObject with the information of my POJO:
public String buildUserJSON(User user) {
JSONObject userJson = new JSONObject();
userJson.put("idUser", user.getIdUser());
...
return userJson.toString();
}
And then call this method in my RestController to build the JSON that I want to return. As I said I do not know what was the problem but at least this was the solution for me.
Note: I found the solution to this be cause in the past I was with a problem similar like this one but when I was trying to return a List<T> as a JSON, so, I though that was related with the same thing.
Regards.
The problem was with Jackson, so to get out of this problem you most use two annotations in the relations of your entities.
More information, please see the next link: Here is the answer
Hope it can help for anyone.

Spring Boot Repository.save() methods do not work - No commit

I scan two QR code and try to get them from My QR Code Android Mobile App and save it with repository.save() in my Local db.
My app send List to Backend but don't insert to db. When I run localhost/8090, i don't get back anything.
In Browser show only this:
-Find Devices
-Device Code
-Device ID
Developer.java
#Entity
public class Developer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id = 0;
private String deviceCode;
private String deviceId;
public Developer() {
super();
}
public Developer(String deviceCode, String deviceID)
{
super();
this.deviceCode = deviceCode;
this.deviceId = deviceId;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String deviceCode() {
return deviceCode;
}
public void set DeviceCode(String deviceCode) {
this.deviceCode;
}
public String deviceId() {
return deviceId;
}
public void set DeviceId(String deviceId) {
this.deviceId;
}
}
DeveloperRepository.java
import org.springframework.data.repository.CrudRepository;
public interface DeveloperRepository extends CrudRepository<Developer, Long> {
}
DeveloperController.java
#Controller
public class DevelopersController {
#Autowired
DeveloperRepository repository;
#RequestMapping(value = "/", method = RequestMethod.POST)
#ResponseBody
private String addDevices(Developer deviceCodeAndId) {
System.out.println("xyz!");
if (!repository.exists(deviceCodeAndId.getId())) {
repository.save(deviceCodeAndId);
return "successfully added " + deviceCodeAndId.getId();
}
return deviceCodeAndId.getId();
}
#RequestMapping(value = "/showall",method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("index",repository.findAll());
return "index";
}
}
deviceCodeAndID is Class from Android App which scanned with app!
index.html
Have you enabled transaction management. Even you use Spring boot data repository. You need to enable transaction management, else by default everything will be read mode. And for read mode there is no need to transaction. But when you do any operation that will change data in DB, you need to perform transaction management.
Use #EnableTransactionManagement on in application class, and #Transactional in DAO or service class
#SpringBootApplication
public class Application {
#Autowired
DeveloperRepository developerRepository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
Here is my Application Class

Spring session bean and RESTEasy + Jackson nullPointerException

I am building a spring based WebApp including a RESTful method call.
I use RESTeasy and jackson to return the username of the current logged in user
(this information is stored in a session bean called "UserBean")
UserBean:
#Component("userBean")
#Scope("session")
public class UserBean implements Serializable {
#Autowired
private InitApp app;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
OverviewBean is the bean that contains the rest method (including the jackson conversion to json):
#Component("overviewBean")
#Scope("view")
#Path("/repairs")
public class OverviewBean {
#Autowired
private InitApp app;
#Autowired
private UserBean userBean;
private List<Repair> openRepairsClient;
private List<Repair> closedRepairsClient;
#PostConstruct
public void fillRepairs() {
try {
String username = userBean.getUsername();
openRepairsClient = app.repairService.findOpenRepairsByClient((Client) app.userService.getUser(userBean.getUsername()));
closedRepairsClient = app.repairService.findClosedRepairsByClient((Client) app.userService.getUser(userBean.getUsername()));
} catch (UserServiceException ex) {
Logger.getLogger(OverviewBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Getters and setters openRepairsClient/closedRepairsClient
#GET
#Path("/getrepairs")
#Produces("application/json")
public String getOpenRepairsInJson() {
String username = userBean.getUsername();
return "test";
}
}
fillRepairs() is able to use userBean without any errors. For example the "String username = userBean.getUsername();" within the try catch returns the username correctly.
My issue is that when getOpenRepairsInJson gets called it throws a nullPointerException
on "String username = userBean.getUsername();". It seems that my userBean is not "linked"
at the moment of the method call. What am I doing wrong?
Thanks in advance!

Hibernate automatic versioning not working (with Spring)

I am trying to use the automatic versioning of Hibernate but when the update method f of the Session is called I do not see the version field in the where clause of the query nor is the version incremented in the database. I am doing something fundamentally wrong probably, but what? Is calling getCurrentSession of sesssionFactory an issue?
I have the following entity class:
package dslibweb.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
#Entity
#Table(name = "dsXCT_Recalls")
public class DsXCT_Recalls {
#Id
public String recallId;
public int version;
public String status;
//...... more properties.....
#Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getRecallId() {
return recallId;
}
public void setRecallId(String recallId) {
this.recallId = recallId;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
My controller:
package recalls.controller;
#Controller
public class RecallsDataController {
#Autowired
RecallsService recallsManager;
#Autowired
AuthenticationService authService;
private static final Logger logger = Logger.getLogger(RecallsDataController.class);
private static final String SAVE_RECALLS = "MODIFY XCT RECALLS";
RecallsGrid recalls;
#RequestMapping(value = "/showRecallsGrid")
#ResponseBody
public RecallsGrid showRecallsGrid( HttpSession session, HttpServletResponse response) {
recalls = recallsManager.getRecallsDataGrid((String) session.getAttribute("socketToken"), new GridFilters(0, 0, "", "", "", "", ""));
if (recalls.getError() == null || recalls.getError().equals("")) { // no error
return recalls;
} else {
try {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, recalls.getError());
} catch (IOException e) {
e.printStackTrace();
}
return recalls;
}
}
#RequestMapping(value = "/saveRecalls" , method= RequestMethod.POST)
#ResponseBody
public String saveRecalls( HttpSession session, #RequestParam(value="ids[]", required = false) String [] ids, #RequestParam(value="statuses[]", required = false) String [] statuses){
boolean result = authService.validateUserAction((String) session.getAttribute("socketToken"), SAVE_RECALLS);
if(result)
return recallsManager.saveRecalls(ids, statuses, recalls);
else
return "You do not have authority to perform this action.";
}
}
Where I retrieve a collection of DsXCT_Recalls and show them to the user. The collection is stored in the controller. The user then changes status in one or more entities and I call the saveRecalls method of the recallManager which creates a list of only the changed entities (comparing with the collection stored in the controller).
The recallsManager (service layer) is:
package recalls.service.defaultimpl;
#Service("recallManager")
public class HibernateRecallsDataService implements RecallsService {
#Autowired
JsonRpcRequest jsonReq;
#Autowired
JsonRpcSocketWriterReader socketWriterReader;
#Autowired
JsonRpcRequestConstructor reqConstructor;
#Autowired
RecallsDao hibernateRecallsDao;
private static final Logger logger = Logger.getLogger(HibernateRecallsDataService.class);
#Transactional
public RecallsGrid getRecallsDataGrid(String socketToken, GridFilters filters) {
List<DsXCT_Recalls> recalls = hibernateRecallsDao.findRangeOfRecordsFiltered(filters);
return new RecallsGrid(recalls);
}
#Transactional()
public String saveRecalls(String[] ids, String[] statuses, RecallsGrid recalls) {
List<DsXCT_Recalls> recallList = recalls.getRecalls();
List<DsXCT_Recalls> updatedRecallList = new ArrayList<DsXCT_Recalls>();
for (int i = 0; i < ids.length; i++) {
for (DsXCT_Recalls recall : recallList) {
if (recall.recallId.equals(ids[i])) { // recall is found in the list
if (!statuses[i].equals(recall.getStatus())) { // status has changed
recall.setStatus(statuses[i]);
updatedRecallList.add(recall);
}
}
}
}
return hibernateRecallsDao.saveAll(updatedRecallList);
}
}
The saveAll method of my DAO calls one update method of hibernate session by entity changed:
package recalls.dao.hibernate;
#Repository
public class HibernateRecallsDao implements RecallsDao {
#Autowired(required = true)
#Resource(name = "mySessionFactory")
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public List<DsXCT_Recalls> findRangeOfRecordsFiltered(GridFilters filters) {
return sessionFactory.getCurrentSession().createQuery("from DsXCT_Recalls r WHERE SID = 0 ORDER BY Org, Bank, BIC, SetlDate").list();
}
public String saveAll(List<DsXCT_Recalls> recallList){
int count = 0;
for(DsXCT_Recalls recall:recallList){
sessionFactory.getCurrentSession().update(recall);
count++;
}
return count + " recalls were modified.";
}
}
So apparently the #Version must be above the attribute declaration and not above the getter method.. I am sure I saw this somewhere though. So much time wasted :(

Integrating JPA2.0 and Spring

last few hours I try to test with spring jpa 2.0 3.0
Finally I could recover objects persisted
but when I try to persist a new object I receive the following error message:
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:306)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.orm.jpa.JpaAccessor.translateIfNecessary(JpaAccessor.java:152)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:188)
at org.springframework.orm.jpa.JpaTemplate.flush(JpaTemplate.java:288)
at myPackage.testDAO.create(testDAO.java:33)
at myPackage.Main.main(Main.java:27)
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:789)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy21.flush(Unknown Source)
at org.springframework.orm.jpa.JpaTemplate$8.doInJpa(JpaTemplate.java:290)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:183)
... 3 more
my entity bean:
#Entity
public class Application implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="ID_APPLICATION")
private long idApplication;
#Temporal( TemporalType.DATE)
#Column(name="DATE_LIVRAISON")
private Date dateLivraison;
#Lob()
private String description;
#Column(name="NOM_APPLICATION")
private String nomApplication;
private String url;
//bi-directional many-to-one association to Test
#OneToMany(mappedBy="application")
private List<Test> tests;
public Application() {
}
public long getIdApplication() {
return this.idApplication;
}
public void setIdApplication(long idApplication) {
this.idApplication = idApplication;
}
public Date getDateLivraison() {
return this.dateLivraison;
}
public void setDateLivraison(Date dateLivraison) {
this.dateLivraison = dateLivraison;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getNomApplication() {
return this.nomApplication;
}
public void setNomApplication(String nomApplication) {
this.nomApplication = nomApplication;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public List<Test> getTests() {
return this.tests;
}
public void setTests(List<Test> tests) {
this.tests = tests;
}
}
my repository:
#Repository
public class testDAO extends JpaDaoSupport implements ItestDAO {
#PersistenceContext
private EntityManager em;
public List<Application> findALL() {
// TODO Auto-generated method stub
return null;
}
public Application findById(long id) {
// TODO Auto-generated method stub
return getJpaTemplate().find(Application.class, id);
}
public void create(Application application) {
getJpaTemplate().persist(application);
}
}
findById method works normally (which reassures me that jpa configuration is correct), but when I run the create method I receive the above error message.
ApplicationContext context=new ClassPathXmlApplicationContext("application-context.xml");
testDAO dao=(testDAO)context.getBean("dao");
Application application=new Application();
application.setIdApplication(2);
application.setUrl("url");
application.setDescription("description");
application.setNomApplication("dsdsds");
dao.create(application);
any help are appreciated
Thank you for your help
In short, methods of EntityManager such as persist, remove, merge must be called inside a transaction, hence the error message which is actually self explaining:
javax.persistence.TransactionRequiredException: no transaction is in progress
Spring provides support for transaction management (see links below), including when writing tests... if you use one of the Spring testing class providing transactional support.
See also
10. Transaction Management
10.5 Declarative transaction management
10.5.6 Using #Transactional

Categories