I'm no pro with Java, so I need a little help. I'm using the Play Framework.
I have an Entity class which extends GenericModel with fields like the following:
#Column(name = "description")
private String description;
I want to add an additional field using a getter, let's call it getToString, which basically contains a read only string with the string representation of the entity.
I need this because the object is getting sent as a JSON response, and my JavaScript will read this field, and display it where for example the entity needs to be represented as a string.
How do I go about doing this?
I'm no expert on the Play framework, but probably you should have a look at the #Transient annotation.
Fields (and getters/setters if you are using JPA property access) marked with #Transient will be ignored by JPA, but usually be considered by other frameworks.
The problem I'm having was a side effect of using GsonBuilder. The builder doesn't appear to be parsing getters and setters, unless the source of the library is modified, which I'm not willing to do.
For what I understand (please correct me if I'm wrong) you want a read-only method that will return a string representation (JSon format) of the entity.
You could just override the default toString method:
#Override
public String toString() {
return "your_json_string";
}
and call it when needed
Related
I am trying to add a simple controller method, but I am running into the following
Exercise.java:[13,1] variable id might not have been initialized
Here is the code that I am working with
#RequestMapping(value = "/exercises/{id}")
public ResponseEntity<Optional<Exercise>> getExerciseById(Model model, #PathVariable Integer id) {
Optional<Exercise> exercise = exerciseRepository.findById(id);
if(id!=null)
return new ResponseEntity<Optional<Exercise>>(exercise, HttpStatus.OK);
else
return new ResponseEntity<Optional<Exercise>>(exercise, HttpStatus.NOT_FOUND);
}
I am using an Optional<Exercise> here because I am taking advantage of the build in method findById from the JpaRepository package. I haven't found any good posts on how to handle this is. This is probably something simple. I've found some documentation around this:https://www.java67.com/2016/07/how-to-fix-variable-might-not-have-been-initialized-error-in-java.html, but I could use a little help understanding the best way to fix this. This is the exercise classe
#Entity
#Table(name = "exercise")
#Value
#NoArgsConstructor
public class Exercise {
#Id
#NonNull
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private int chapterId;
private String exercise;
private String answer;
private String question;
private String a;
private String b;
private String c;
}
tldr;
I don't think JPA plays well with the immutable entity created by #Value. Use #Data instead.
ihnbtdttrt (i have nothing better to do than to read this);
This partially guesswork, but since it has seemed to help, this is what I think is happening:
When you call findById(), JPA creates a new entity object using a no-argument constructor, and then sets the fields individually afterwards. (I'm not sure if it uses setters or sets the fields directly using reflection).
The #Value annotation, as documented here, makes a class immutable, with all the fields private and final and with no "setters" created. This means that the only way to set the fields is by passing the field values into a constructor with appropriate arguments. After that the fields are not changeable.
Since JPA initializes entities using the no-args constructor and tries to set the fields afterwards, with your setup, it uses the no-args constructor and ends up with an entity object where none of the fields have been initialized but none of them are modifiable after the constructor. All private, final fields, with no setters. Then it tries to call entity.getId(), and the id field hasn't been initialized, leading to the above error.
To fix this, you can use the #Data annotation instead of #Value. This is similar, but doesn't create an immutable object. In particular, it generates "setter" functions and the fields are not set to final. This is the type of Java bean that JPA expects, one that can be initialized with a no-argument constructor and then have the fields set afterwards.
There may be ways to configure JPA to create objects differently, so that it passes all the data into a constructor so that you can have immutable entities. I know that some Spring DI stuff is configurable to initialize using rich constructors like this, but Idk about JPA.
For what it's worth, I appreciate the value of immutable objects for clean code, but it's not uncommon to find the above pattern of no-arg construction + post-construction setting when using the popular Java frameworks like JPA/Hibernate, Spring, etc. They don't always play well with immutability.
We use JSON serialization with Jackson to expose internal state of the system for debugging properties.
By default jackson does not serialize transient fields - but I wish to serialize them as well.
How can I serialize these fields?
One way I know is to supply a getters for these fields - but I don't want to do that, as I have some getX methods that I don't want to be invoked ( for instance, there are some getters that change the objects state ).
I know I could create an annotation, but I really want to avoid it.
So my question is:
Is there a way to setup jackson to serialize all the objects fields? include transient ones.
My solution with Jackson 2.4.3:
private static final ObjectMapper mapper =
new ObjectMapper(){{
Hibernate4Module module = new Hibernate4Module();
module.disable(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION);
registerModule(module);
}};
I don't think Jackson supports any type of configuration to enable it to serialize a transient field. There's an open issue to add that feature, but it's old and hasn't been addressed (as far as I can tell): http://jira.codehaus.org/browse/JACKSON-623
So my question is: Is there a way to setup jackson to serialize all
the objects fields? include transient ones.
So to answer your question, no.
Some other Java JSON tools, such as GSON do support a configuration option to serialize transient fields. If you can use another tool, you might look into that (for GSON, see: https://sites.google.com/site/gson/gson-user-guide).
To expand a little, you might try a different approach.
First, You shouldn't try to serialize a transient field. After all the definition of transient is "don't serialize this." Nevertheless I can think of a few specific situations where it might be necessary, or at least convenient (like when working with code you can't modify or such). Still, in 99% of cases, the answer is don't do that. Change the field so that it's not transient if you need to serialize it. If you have multiple contexts where you use the same field, and you want it serialized in one (JSON, for example), and not serialized in another (java.io, for example) then you should create a custom serializer for the case where you don't want it, rather than abuse the keyword.
Second, as to using a getter and having "some getters that change the objects state," you should try to avoid that too. That can lead to various unintended consequences. And, technically, that's not a getter, that's a setter. What I mean is, if it mutates state, you've got a mutator (setter) rather than accessor (getter), even if you name it following the "get" convention and return some stuff.
You can create a custom getter for that transient field and use #XmlElement attribute. It doesn´t matter the name of that getter.
For example:
public class Person {
#XmlTransient private String lastname;
#XmlElement(name="lastname")
public String getAnyNameOfMethod(){
return lastname;
}
}
Another way to let Jackson serialize property is to add #JsonProperty annotation above it.
I guess it's better approach cause you do not need to disable default behaviour for all #Transient fields, like in Gere's answer.
I have created dynamic setter getter using Reflection API but it is creating performance issue so I want to replace my reflection code with some dynamic cutom method specially for getter.
I am planning to store all my field name in map but not sure how will I link my accurate values agains those fields.
I have tried with PropertyUtils as well but it also use reflection internally.
In the case of reflection it was working fine.
Is there any way to write dynamic getter value with fieldname verified because if i will store fields name in map on first attempt as key and value as null then how will i link specific value for that field after that and again it will be lengthy process.
Use Lombok for that https://projectlombok.org/. It will generate boilerplate getter/setters for you on precompile.
it will be like
#Getter
#Setter
public class LombokExample(){
private String myField;
}
done - end of class definition - no getters/setters required
and still you will be able to
lombok=new LombokExample();
lombok.getMyField();
lombok.setMyField();
I have Entity:
public class User {
private Long id;
private String name;
private String lastName;
private String email;
private String password;
// getters and setters
}
I would like to use it as a Form Backing Object in presentation layer, but it doesn't have fields that I need. In this case I need repeatedPassword field.
What is the best approach to this problem without modifying entity class?
Should I extend this entity class and add needed fields?
Should I create new class which has a field private User user; with getter and setter?
Should I copy/paste this class and then add needed fields?
Three different solutions:
The usual way of dealing with a situation where the input fields on a form don't match up with an entity is to use a Command object (this is what Sotirios was advocating in the comments). Making a separate object for this that is not an entity is much less confusing than extending the entity to add something unrelated to persistence.
It be argued in this case there's no need to pass the repeatedPassword field back to the server, the validation could be done entirely on the client, and the input field doesn't need to be bound to a Java pojo at all.
If you really want to pass the repeatedPassword back to the server (so you can do all your validation on the server-- although the repeated password is more of a user convenience than real validation), then you could add the repeatedPassword field to the User entity with a #Transient declaration.
I'm trying to deserialize JSON Object coming from an application I can't control. Here my JSON :
{"assembly":
{"name":"mm9",
"id":32,
"chromosomes":[
{"chromosome":
{"name":"MT"}
}]}}
My Pojos, are
class Assembly{
private String name;
private int id;
private ArrayList<Chromosome> chromosomes;
// getters & setters
}
class Chromosome {
private String name;
//getter/setters
}
But it's not working because of the extra fields "assembly" & "chromosome", so with a JSON like :
{"name":"mm9",
"id":32,
"chromosomes":[
{"name":"MT"}
] }}
it simply working.
Is there a way to modify configuration or something to achieve this without create more complex POJOS?
The problem is that in the first JSON snippet, chromosomes is a dictionary (Map), of which one of the entries (chromosome) happens to correspond to your Chromosome object.
A more accurate direct mapping to a Java class would be
class Assembly{
...
private Map<String, Chromosome> chromosomes;
}
Since you mention you can't control the format of the source JSON, you may want to look into using custom deserializers, or perhaps using the streaming support from Jackson rather than ObjectMapper for direct mapping, if you aren't happy changing your POJOs in this way.
By the way, it is best to refer to collections by their interface type (List) rather than a concrete type (ArrayList). It is very unlikely that code that refers to this class truly cares or needs to know that it is using an ArrayList, referring to just the List interface instead makes it a lot easier to swap other implementations in if needed (as a general principle).