I have a class that implement all my workflow method. At some pointing time, when the request is approved by the workflow, I need to update status in database. For this I need to call the respective service class to save the status. The following method is saving the status in db:
public void changeStatus(String employeeNumber, String carid,String Status) throws Exception {
Car car = carService.findCarByPrimaryKey(carid);
car.setStatus(Status);
carService.saveCarDetails(car);
}
I want to make this method generic since I don't have status for car only. I have to update status for different object depending from the application made. It can be for application for leave/parking...I can keep the field Status with the same name in all table. Please advise me how to proceed.
Thanks
I am not sure , what ORM you are using , like if JPA you are using , you can use find() with class name and primary key as parameters.
May be you can try adding a parameter in changeStatus() as Class class and while calling this changeStatus() method pass the class variable by using getClass() and can perform actions basis of that in changeStatus()
Related
Recently I was working on a little RESTful API using Spring and I came across the ModelAttribute annotation.
I noticed that there is some very interesting behavior associated with it, mainly the fact that you can stick it onto a method and it will get called before the handler for a given request is called, allowing you to do anything before data is bound to the arguments of your handler method.
One usage that comes to mind is default values:
#ModelAttribute("defaultEntity")
public Entity defaultEntity() {
final var entity = new Entity();
entity.setName("default name");
return entity;
}
#PostMapping("/entity")
public Entity createNewEntity(#Valid #ModelAttribute("defaultEntity") Entity entity) {
dao.saveEntity(entity);
return entity;
}
In this case, when a POST request comes to /entity, the first thing that will happen is that defaultEntity will get called, creating an entity with some default values pre-filled. Then, Spring will bind the incoming data into it (potentially overwriting the defaults or keeping them as-is) and then pass it into the createNewEntity handler. This is actually pretty nice, IMO.
Another surprising fact is that the annotated method can actually take parameters in much the same way as the handler method. A simple way to do partial entity updates could be something like this:
// first fetch the original entity from the database
#ModelAttribute("originalEntity")
public Entity originalEntity(#PathVariable("id") long id ) {
return dao.getEntity(id);
}
// then let Spring bind data to the entity and validate it
#PostMapping("/entity/{id}")
public Entity updateEntity(#Valid #ModelAttribute("originalEntity") Entity entity) {
// and finally we save it
dao.saveEntity(entity);
return entity;
}
Again, this is surprisingly easy.
Even more surprising is that different model attributes can depend on each other, so you can have a complicated multi-stage monster if you want:
// first fetch the original entity from the database
#ModelAttribute("originalEntity")
public Entity originalEntity(#PathVariable("id") long id ) {
return dao.getEntity(id);
}
// then let Spring bind data to the entity, validate it and do some processing to it
#ModelAttribute("boundAndValidatedEntity")
public Entity boundAndValidatedEntity(#Valid #ModelAttribute("originalEntity") Entity entity) {
processEntity(entity);
return entity;
}
// finally check that the entity is still valid and then save it
#PostMapping("/entity/{id}")
public Entity updateEntity(#Valid #ModelAttribute(value = "boundAndValidatedEntity", binding = false) Entity entity) {
dao.saveEntity(entity);
return entity;
}
Obviously not all of the model attributes have to be of the same type, some can depend on multiple arguments from different places. It's like a mini-DI container within a single controller.
However, there are some drawbacks:
as far as I can tell, it only works with query parameters and there is no way to make it work with other kinds of request parameters, such as the request body or path variables
all of the ModelAttribute-annotated methods within a single controller will always be called, which can
have a performance impact
be annoying to work with, since Spring will need to be able to gather all of the method's arguments (which may be impossible, for example when they reference a path variable that doesn't exist in the current request)
So, while ModelAttribute doesn't really seem too useful by itself because of these issues, I feel like the main idea behind it - essentially allowing you to control the construction of a method's parameter before it's bound/validated while being able to easily access other request parameters - is solid and could be very useful.
So, my question is simple - is there anything in Spring that would essentially act like ModelAttribute but without the drawbacks that I mentioned? Or maybe in some 3rd party library? Or maybe I could write something like this myself?
I'm trying to implement a method for updating a database record. So far, I created this one:
public Optional<User> update(final Integer id,final UpdateUserDto dto) {
userRepository.findById(id).ifPresent((user -> {
user.setShop((dto.getShopId() == null) ? null : shopRepository.findById(dto.getShopId())
.orElseThrow(ShopNotFoundException::new));
user.setUsername(dto.getUsername());
user.setPassword(passwordEncoder.encode(dto.getPassword()));
user.setRoles(Arrays.asList(
roleRepository.findByRoleName(dto.getRole()).orElseThrow(RoleNotFoundException::new)
));
}));
return userRepository.findById(id);
}
But now I added two more fields to my user entity (activated, productAllowed) and I must enhance my update method to make them updatable. I can do that, but I have other entities also and if I change them it will be a lot of maybe boilerplate code.
Is there any kind of best practice to do this in a better way, or I just need to keep setting all the fields manually?
I was also thinking about reflection, but in that case I have a few fields that cannot be copied exactly from the DTO to the entity (e.g. the shop field, which is queried from database, or role field).
And I also don't think that another query for returning the new object is effective, but although I set the properties in a service layer, the original findById()'s returned user is wrapped inside an Optional, so I don't think it will be updated.
Thank you in advance.
I have several classes, all of which have an ID field declared as Integer the next way:
#Expose
#DatabaseField(columnName = "_id", id = true)
private Integer idField;
Everything compiles and runs correctly, but when I simply try to check if a record exists:
Integer idField = 1;
result = DBHelper.getHelper().getClassDAO().idExists(idField);
I get the exception:
java.sql.SQLException: Field '_id' is of data type null which can not be compared
The thing is that with one class (let's name it A) the method works properly, but with the others fail and I don't know which is the cause because all the classes have its ID field declared the same way.
I'm getting this exception too if I try to createOrUpdate the object of any class, except the refered class A.
Any helping hand would be appreciated.
NOTE. The project uses an ormlite_config.txt file, which is updated.
After a few hours debugging I came into that the mentioned exception comes only when the class to be saved has one o more collections. As far as I know, the exception is thrown inside the idExists method of the Dao class. Having in mind that the createOrSave method surely must call it, that's why I get the SQLException in both cases.
And now, the workaround to solve this. Rather than invoking the idExists method, I had to create my own like this:
return DBHelper.getHelper().getMyDAO().queryForId(idField) != null;
And instead of calling the createOrUpdate method, first I check if the record exists and then, depending on the result, I call the create or update method of the Dao class I want to persist.
Like many others have noted, the ACL seems like overkill for executing such a conceptually simple thing in a case like this.
I am looking for a simple implementation of the following scenario in Spring Security:
I have a method in a controller which handles a delete request for an event entity. I need the #PreAuthorize expression that will check to make sure that the ID of the user submitting the request matches the ID of the owner of the request. Perhaps through an Event.getOwner().getId() method.
How would this look? Thanks.
I'm thinking something like. The following method in the Event controller:
#PreAuthorize("#event.getOwner().getId() == authentication.id")
public void delete(#PathVariable("id") final Long id, #RequestBody final Event event) {
repo.delete(id, event);
}
And if this is the correct use, where does #event come from? In other words, what is signified by the '#'? I ask because at this point we are in the controller, so, which Event is #event referring to?
Your idea is not safe. It requires that the event information including owner is sent as request body in the delete request. With this the client can spoof the owner to be of the current user instead of the actual owner.
Assuming that id is the unique id of an event, I would suggest something like the following as a minimal solution:
#RequestMapping(value="/{id}", method=RequestMethod.DELETE)
#PreAuthorize("#repo.getOwnerOfEvent(#id) == authentication.name")
public void delete(#PathVariable("id") final Long id) {
repo.deleteEvent(id);
}
The above snippet requires a bean named "repo" that contains the method:
/**
* Returns the owner username of the event with the specified id.
*/
String getOwnerOfEvent(long id);
I am using Spring Data to load an object and all works well...However, I don't want to load the entire object as I am returning a list to display in a table, so I only want to load what is in the table. then, when a user selects "details" I want to make an AJAX call to the server to load the entire object. My thought was to have a Base Class "TableView" then to have a subclass "Class DetailsView extends TableView". I could probably create a new repository, so one for the TableView and one for the DetailsView, but I'm wondering if there is a way to use the same repository class? below is an example of what I'd like to do, but I'm not sure how to change the repositoryClass to achieve what I want...I get the following error:
SQLGrammarException: could not extract ResultSet at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:261)
class TableView{
String title;
}
class DetailsView extends TableView{
String details;
}
interface ITableViewRepository extends CrudRepository<TableView, Integer>{
You can write two queries in your TableViewRepository.
One for returning id and title from you object
#Query("SELECT tv.id, tv.title FROM TableView tv")
TableView findWithTitles();
And after that just call a method findOne with TableView id to return entire object.