I am new to the automatic generation of REST services code from a Database in Netbeans 8.
Disclaimer: after a discussion (in the comments), I realized that I
should warn to avoid this question if you are not familiar with the
automatic generation of REST service from DB in Netbeans
(https://netbeans.org/kb/docs/websvc/rest.html). That's because you
need to know what is going on and where to put your hands in order to
edit them. I don't provide any non-working code here, rather I want to know what should I do in order to edit such services. I provide an example of what I would like to obtain.
I did the automatic code generation of REST services from DB and obtained entity classes and service "facade" classes. What I need to do now is to extend / edit those services and I don't know where to put my hands.
For instance, consider the following scenario. I have a student and he/she passed many exams. From the DB perspective, student-exam is a 1 to many relationship.
When I test the rest API and perform a GET by ID of a student, the resulting JSON does not contain a collection of exams associated with that student, as expected.
Where and how should I change the auto-generated service code in order to obtain the exams collection within the student's json?
In other words, assuming I perform a GET to
../student/12, what I want to obtain is:
{
"id":12, "name":"Marco", "age":26, "exams": [
{ "id":1, "exam_name":"Computer Networks" },
{ "id":15, "exam_name":"Algorithms"}
]
}
Best regards
So it seems like I got it working, but I don't know if this is the most elegant way to do it.
Here's what I did.
1) go to the auto-generated child entity class (i.e. Exam.java) and add a custom NamedQuery to the NamedQueries annotation. For instance,
#NamedQueries({
... default auto-generated stuff ...
#NamedQuery(name = "getExamsOfStudent", query="SELECT e FROM Exams e WHERE e.student.ID =: studentID")})
2) go to the auto-generated child REST service class (i.e. ExamFacadeREST.java and add a method to retrieve the children of a parent, using the NamedQuery defined in the entity class. For instance,
#GET
#Path("studentID/{studentID}")
#Produces({"application/xml","application/json"})
public List<Exam> getExamsOfStudent(#PathParam("studentID") Integer studentID) {
javax.persistence.Query query = getEntityManager().createNamedQuery("Exam.getExamsOfStudent");
query.setParameter("studentID", studentID);
return query.getResultList();
}
At this point you have a REST service that retrieves the children of a parent entity.
However, this is not what I originally asked for. I would like to retrieve the exams as a collection, inside the student JSON, when performing the GET (by id) of the student.
In order to do so simply go to the father entity REST service, (i.e. StudentFacadeREST.java) and properly edit the find method.
Does anyone know a more elegant way to do it?
EDIT 1: I'm trying the second method (to retrieve the exams as a collection, inside the student JSON, when performing the GET of the student) and I see that the collection does not get serialized into the output JSON. Any advice on this?
EDIT 2: I got it. For "generally extending" a service the first part of my answer above is good. However, if you want to obtain the serialization of collections that are already mapped as relations in the DB, simply properly remove the relative #XmlTransient annotations in the entity auto-generated classes. Take care to avoid circular references, that is you will probably need to add an #XmlTransient annotation to the "getParent()" method in the child entity class.
For this example:
(A) go to the Student entity class and remove the #XmlTransient annotation from the getExamsCollection() method;
(B) go to the Exam entity class and add the #XmlTransient annotation to the getStudent() method.
Hope this helps.
Best regards
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'm creating a website for a school project which uses spring for the backend. I'm trying to insert data into the database when new data is saved to a specific table.
I've tried using #HandleAfterCreate and #PrePersist, but neither worked. I'm not very experienced with spring. The teacher told us to use it and now I don't know what do.
#HandleAfterCreate
public void handlePersonBeforeCreate(Person person){
logger.info("Inside Person Before Create....");
Set<Qualifikation> qualifikationen = new HashSet<>();
kompetenzRepository.findAll().forEach(kompetenz -> {
Qualifikation qualifikation = new Qualifikation();
qualifikation.setAusmass(0);
qualifikation.setKompetenz(kompetenz);
qualifikation.setPerson(person);
});
person.setQualifikationen(qualifikationen);
System.out.println(person.getDisplayName());
}
The code should set a person's "Qualifikation" to a default value when the person is inserted (via OAuth login). It should have every "Kompetenz" with a value of 0 by default. Kompetenz has a 1 to n relation to Qualifikation. If you need more information please ask me.
It looks like you're trying to have access to the repository layer of your application inside an entity. This is generally not a good idea, as the entities should only know about the data they hold, not the other application components.
In this particular case it would be wise to use a #Service class with a method that you can call to insert the data into the database. In the method you could then insert any other entities as well. Let your repositories be fields of the service and make them #Autowired.
I think you need to enable JPA auditing . It can be enabled in Spring by add #EnableJpaAuditing to your persistence configuration. This tells Spring to listen JPA entity lifecycle events and call the annotated methods in appropriate places.
Also I think you should make the callback method private if it is meant to be called only when persisted (#PrePersist).
See details here. In this article is also presented entity listeners which might also be a good solution when dealing with multiple entities having a need for same pre-persist functionality.
I think you should create a service class, a repository class and an entity which will be stored through repository. The logic of getting all inner elements and filling it with default value is to be written in service and not a good idea to write in entity class.
If you need any help regarding it, let me know .
Welcome to community!!
I have an entity which looks something like this: (I'm coding to the web page so I apologize for any mistakes)
#Entity
public class Entity {
#Id
private Long id;
private String field;
// Insert getters and setters here...
}
I try to manipulate it using reflection:
Long id = 1;
Entity entity = myDao.getEntity(id);
entity.setField("set directly");
Field[] fields = entity.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.getName().equals("field")) {
f.setAccessible(true);
f.set(entity, "set using reflection");
f.setAccessible(false);
}
}
System.out.println(entity.getField());
This program prints "set using reflection". However, in the database the value set using reflection does not get updated:
SELECT * FROM ENTITY WHERE ID = 1
ID FIELD
1 set directly
This is strange. I could swear that this used to work - but now it isn't. Is it really so that you cannot manipulate entities using reflection?
I'm using EclipseLink 1.1.1 if that matters.
Changing values of an entity class by reflection is going to fraught with issues. This is because you're dealing with a class which is persistent and thus the persistence API needs to know about changes to the fields.
If you make changes via reflection, chances are the persistence API will not know about those changes.
A better solution would be to call the setters via reflection.
I'm pretty sure the Entity you are given by your persistence framework is actually wrapped in another class (possibly the same with stuff tacked on through reflection). Changing the field directly through reflection seems unlikely to work. You might want to check if there's a (generated) setter that you can use. Although if you're going that route one might ask why you don't allow callers to call the setter directly?
Your class might be instrumented and the setters responsible for recording changes. I'm not familiar with EclipseLink to check if the class returned by myDao.getEntity(id); is your actual class of a sub-class generated by EclipseLink.
I have a unidirectional relation Project -> ProjectType:
#Entity
public class Project extends NamedEntity
{
#ManyToOne(optional = false)
#JoinColumn(name = "TYPE_ID")
private ProjectType type;
}
#Entity
public class ProjectType extends Lookup
{
#Min(0)
private int progressive = 1;
}
Note that there's no cascade.
Now, when I insert a new Project I need to increment the type progressive.
This is what I'm doing inside an EJB, but I'm not sure it's the best approach:
public void create(Project project)
{
em.persist(project);
/* is necessary to merge the type? */
ProjectType type = em.merge(project.getType());
/* is necessary to set the type again? */
project.setType(type);
int progressive = type.getProgressive();
type.setProgressive(progressive + 1);
project.setCode(type.getPrefix() + progressive);
}
I'm using eclipselink 2.6.0, but I'd like to know if there's a implementation independent best practice and/or if there are behavioral differences between persistence providers, about this specific scenario.
UPDATE
to clarify the context when entering EJB create method (it is invoked by a JSF #ManagedBean):
project.projectType is DETACHED
project is NEW
no transaction (I'm using JTA/CMT) is active
I am not asking about the difference between persist() and merge(), I'm asking if either
if em.persist(project) automatically "reattach" project.projectType (I suppose not)
if it is legal the call order: first em.persist(project) then em.merge(projectType) or if it should be inverted
since em.merge(projectType) returns a different instance, if it is required to call project.setType(managedProjectType)
An explaination of "why" this works in a way and not in another is also welcome.
You need merge(...) only to make a transient entity managed by your entity manager. Depending on the implementation of JPA (not sure about EclipseLink) the returned instance of the merge call might be a different copy of the original object.
MyEntity unmanaged = new MyEntity();
MyEntity managed = entityManager.merge(unmanaged);
assert(entityManager.contains(managed)); // true if everything worked out
assert(managed != unmanaged); // probably true, depending on JPA impl.
If you call manage(entity) where entity is already managed, nothing will happen.
Calling persist(entity) will also make your entity managed, but it returns no copy. Instead it merges the original object and it might also call an ID generator (e.g. a sequence), which is not the case when using merge.
See this answer for more details on the difference between persist and merge.
Here's my proposal:
public void create(Project project) {
ProjectType type = project.getType(); // maybe check if null
if (!entityManager.contains(type)) { // type is transient
type = entityManager.merge(type); // or load the type
project.setType(type); // update the reference
}
int progressive = type.getProgressive();
type.setProgressive(progressive + 1); // mark as dirty, update on flush
// set "code" before persisting "project" ...
project.setCode(type.getPrefix() + progressive);
entityManager.persist(project);
// ... now no additional UPDATE is required after the
// INSERT on "project".
}
UPDATE
if em.persist(project) automatically "reattach" project.projectType (I suppose not)
No. You'll probably get an exception (Hibernate does anyway) stating, that you're trying to merge with a transient reference.
Correction: I tested it with Hibernate and got no exception. The project was created with the unmanaged project type (which was managed and then detached before persisting the project). But the project type's progression was not incremented, as expected, since it wasn't managed. So yeah, manage it before persisting the project.
if it is legal the call order: first em.persist(project) then em.merge(projectType) or if it should be inverted
It's best practise to do so. But when both statements are executed within the same batch (before the entity manager gets flushed) it may even work (merging type after persisting project). In my test it worked anyway. But as I said, it's better to merge the entities before persisting new ones.
since em.merge(projectType) returns a different instance, if it is required to call project.setType(managedProjectType)
Yes. See example above. A persistence provider may return the same reference, but it isn't required to. So to be sure, call project.setType(mergedType).
Do you need to merge? Well it depends. According to merge() javadoc:
Merge the state of the given entity into the current persistence
context
How did you get the instance of ProjectType you attach to your Project to? If that instance is already managed then all you need to do is just
type.setProgessive(type.getProgressive() + 1)
and JPA will automatically issue an update effective on next context flush.
Otherwise if the type is not managed then you need to merge it first.
Although not directly related this quesetion has some good insight about persist vs merge: JPA EntityManager: Why use persist() over merge()?
With the call order of em.persist(project) vs em.merge(projectType), you probably should ask yourself what should happen if the type is gone in the database? If you merge the type first it will get re-inserted, if you persist the project first and you have FK constraint the insert will fail (because it's not cascading).
Here in this code. Merge basically store the record in different object, Let's say
One Account pojo is there
Account account =null;
account = entityManager.merge(account);
then you can store the result of this.
But in your code your are using merge different condition like
public void create(Project project)
{
em.persist(project);
/* is necessary to merge the type? */
ProjectType type = em.merge(project.getType());
}
here
Project and ProjectType two different pojo you can use merge for same pojo.
or is there any relationship between in your pojo then also you can use it.