Entity doesn't have fields required for Form Object - java

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.

Related

variable id might not have been initialized Spring Boot Controller with lombok

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.

How to add an object that its class has a different class member to an CSV?

Taking this example:
public class Dog {
private String name;
private Owner owner;
}
public class Owner {
private String name;
private int age;
private String address;
}
How I can add multiple Dog objects to a CSV?
How would they look like in the CSV with their owner object inside it?
How are Java Beans useful in this situation?
There are a few approaches, depending on what you want to accomplish. You could write a function that writes a separate CSV for the owners and dogs, where they could reference each other using a key, like a sql primary key. Or you could simply inline the information into one, maybe with columns like:
dog_name, owner_name, owner_age, owner_address
What Java Beans can allow you to do is what is called serialization, where you let Java handle how to read and write objects from disk. Normally, you'd run into issues where Java does not know how to serialize objects that are nested inside each other, but by using Beans you can still accomplish this. You could do this by making Dog implement java.io.Serializable. Check out this guide from TutorialsPoint.
More info about beans here.

Should equals be burdened by the business logic of the application?

Let's say we have such classes in the Java project:
#Entity
class Person {
#Id
String internalId;
#OneToMany
Set<Profession> profession;
}
#Entity
class Profession {
#Id
String id;
String professionName;
Integer yearsOfPractise;
}
In the business logic the professionName has to be unique per Person.
Is it correct to #override the equals with taking into the account only the professionName field and ingoring the others?
On the one hand such the equals can be handy if this class is handled from the business logic perspective. But such equals can be completely wrong and unhandy in cases when this class will have to be handled from some different perspective.
How to decide it?
Of course, this way you are using a business id, instead of the one that is probably generated by the jpa vendor and as a result, entities, that are manages are equal to the same that aren't.
For example if we create an entity, where the id is generated by the database and save it, the following gives no error:
Entity entity = new Entity();
Entity savedEntity = entityRepository.save(entity); // CrudReporitory
assertFalse(entity.equals(savedEntity));
In most cases it's not what we want. For more details I recommend this article.
You can overide the equals according to your business logic. In my case, I have excluded id.You can modify which fields are used with the lombok library:
https://projectlombok.org/features/EqualsAndHashCode
For Example:
#EqualsAndHashCode(exclude = "id")
public class Foo {
private Integer id;
}
Since, there are two cases:
comparing two entities by equality (content)
comparing two entities by an identifier
You should not override equals to do either or. This would be confusing. Instead use a dedicated function for each. This way you/or anyone else reading the code can choose the correct one and this choice will be obvious to the reader.

Save and load objects without breaking encapsulation

I want to save and load objects to a database without using a ORM (like Hibernate).
Lets say i have the following class:
public class Person {
private int age;
public void birthday(){
age++;
}
}
This class doesn't provide a get-method, so the internal state (age) is encapsulated.
If i want to save the object i need a getter method to do the following:
insert into TABLE_PERSON (id, age) vales (1, person.getAge());
The otherway round i need a setter-method to load the object:
int age = "Select age FROM Person";
person.setAge(age);
But i dont want to break the encapsulation (by implementating additional setter- and getter-methods) just to save and load objects.
Is there any possibility to do this? Maybe some kind of pattern (memento?) or best practise?
Thank you in advance!
You mentioned Memento. There's a variant called Snapshot documented by Grand. Here's the UML class diagram:
Person would be the Originator in the pattern.
You could dump the Memento instance to a binary object in the database.
Note that Memento is an inner class of Originator. The createMemento/setMemento are a kind of single get/set which might be breaking encapsulation if you're a purist. However, the packet of information (the Memento) used on the call is an interface with no methods, so encapsulation of Originator's state is guaranteed. This might even work with an ORM if you map it properly.
Of course, this seems a lot of work just to avoid a get/set. Your Person/age example is not quite realistic (not a great model of a Person). It's quite normal to expose a person's age or date of birth, and exposing that property to persist the object would be OK. Encapsulation doesn't mean don't reveal anything. It means don't expose too much detail.
For example, let's not use age but rather Person.birthday. That could be stored internally as a String in YYYY-MM-DD format or using a Date object. Such detail would not be exposed (it would be encapsulated). This is also done so that you can change it and not affect clients of your class. Anything you hide can be changed without negatively affecting clients.
By exposing a person's birthday, you say "I'm taking the risk that Person will always have a birthday." That part is exposed and thus will be hard to change without breaking clients.
Edit after comments
Public methods (e.g., save and load) in Person can take care of the save/load database operation. They will have access to private fields (age) and can get the job done. You said you're not using an ORM, so then you just do it yourself.
Allen Holub wrote a few articles on exactly that subject. He proposes a Builder and something he calls Reverse Builder pattern.
The way it would work in your case a Person would be responsible for generating a representation of itself. That is to say you define an PersonImporter and PersonExporter interfaces to move data into and out of the Person object. These classes are basically part of the Person design. So:
interface PersonImporter {
public int getAge();
public String getId();
}
interface PersonExporter {
public void setDetails(String id, int age);
}
class Person {
private int age;
private String id;
public Person(PersonImporter importer) {
age = importer.getAge();
id = importer.getId();
}
public void export(PersonExporter exporter) {
exporter.setDetails(id, age);
}
}
This doesn't eliminate getters and setters completely it is controlling it using interfaces.
Holub's Article
This is what I think, may not be perfect.
Encapsulation is done for data hiding. Perhaps, you just don't want someone to set a wrong value to the age attribute.
Maybe you can introduces a wrapper class, which is used by external code and only that class is allowed to use your Person class.
If you create a file with public wrapper class lets say PersonWrapper, that provides getter and setter for age. But these getter and setter can have your desired logic of validations such as what values can be set for age, who can etc. Within the same file, Person class may be defined as private but with plain getter and setters for age param. Your PersonWrapper should only use Person class getter and setter on some predefined conditions.
In this way you may be able to have a better encapsulation.
one way here is the use of mapper classes. Create a PersonMAP that map the class to table and and encapsulate all database operations in that class.
I really don't see how using getters/setters is breaking encapsulation. Getters and setters respect encapsulation. In fact, they're a means to achieving it.

Injecting fields into Java JPA fields

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

Categories

Resources