jackson anotations with lombok #Getter dont work - java

having class, the data goes into the map
#Getter
#ToString
#Builder
//#FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
//#JsonIgnoreProperties(value = {"firstName", "lastName"})
public class User {
// #JsonProperty("id")
private final UUID userUid;
#JsonIgnore
private final String firstName;
#JsonIgnore
private final String lastName;
private final Gender gender;
private final Integer age;
private final String email;
public enum Gender {
MALE, FEMALE
}
public String getFullName() {
return this.firstName + " " + this.lastName;
}
public int getDateOfBirth() {
return LocalDate.now().minusYears(age).getYear();
}
public User(#JsonProperty("userUid") UUID userUid
, #JsonProperty("firstName") String firstName
, #JsonProperty("lastName") String lastName
, #JsonProperty("gender") Gender gender
, #JsonProperty("age") Integer age
, #JsonProperty("email") String email) {
this.userUid = userUid;
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.age = age;
this.email = email;
}
public static User newUser(UUID userUid, User user) {
return User.builder()
.userUid(userUid)
.firstName(user.getFirstName())
.lastName(user.getLastName())
.gender(user.getGender())
.age(user.getAge())
.email(user.email)
.build();
}
}
#JsonIgnore annotations on the field do not work, the fields are displayed in the response.
the data is hidden when I annotate class by #JsonIgnoreProperties or by adding annotations over the getter.
and #JsonProperty above the field generally throws a 500 error ...
It turns out that jackson annotations with lombok #Getter do not work, and it is necessary to annotate getters, or am I doing something wrong?

You can assign attribute access of #JsonProperty to JsonProperty.Access.WRITE_ONLY in order to be able to receive this property but exclude it while serializing a POJO.
#Getter
#ToString
#Builder
public static class User {
private final UUID userUid;
private final String firstName;
private final String lastName;
private final Gender gender;
private final Integer age;
private final String email;
public User(#JsonProperty("userUid") UUID userUid,
#JsonProperty(value = "firstName", access = JsonProperty.Access.WRITE_ONLY)
String firstName,
#JsonProperty(value = "lastName", access = JsonProperty.Access.WRITE_ONLY)
String lastName,
#JsonProperty("gender") Gender gender,
#JsonProperty("age") Integer age,
#JsonProperty("email") String email) {
this.userUid = userUid;
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.age = age;
this.email = email;
}
// the rest code
}
Usage example:
String user = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(
User.builder()
.userUid(new UUID(1, 1))
.firstName("firstName")
.lastName("lastName")
.gender(User.Gender.MALE)
.age(1000)
.email("email#example.com")
.build()
);
System.out.println(user);
Output:
{
"userUid" : "00000000-0000-0001-0000-000000000001",
"gender" : "MALE",
"age" : 1000,
"email" : "email#example.com",
"fullName" : "firstName lastName",
"dateOfBirth" : 1022
}
Note: there are no attributes firstName and lastName, but instead fullName is present because of the public method getFullName() which would be treated by Jackson as a plain getter (I'm sure that was precisely the original intention of the OP, but it's worth to draw the reader's attention to this fact)

Related

List is not in order

I converted UUID to string (String id) and put the conversion inside a method.
I also declared other String variables such as FirstName etc and put in on an ArrayList:
Code
The code does work. But I'm confused why the string email was showing second on the list.
public class StudentController {
#Autowired
StudentService studentService = new StudentService();
#GetMapping
public List<Student> displayStudent(){
return studentService.getStudent();
}
}
public class StudentService {
Student student = new Student();
private List<Student> studentList = Arrays.asList(
new Student(student.genID(),"Elvis" , "Presley" ,"Elvis#gmail.com")
);
public List<Student> getStudent(){
return studentList;
}
}
public class Student {
UUID uuid = UUID.randomUUID();
private String id;
private String FirstName;
private String LastName;
private String email;
public Student() {}
//Method Converting UUID into string
public String genID(){
id = uuid.toString();
return id;
}
public Student(String id) {
this.id = id;
}
public Student(String id, String firstName, String lastName, String email) {
this.id = id;
FirstName = firstName;
LastName = lastName;
this.email = email;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Expected
I expected data to be in this order
ID , FirstName , LastName , email
Actual Output JSON
JSON is an unordered collection, as specified on https://www.json.org/json-en.html , so you don't have to worry about it. It might depend on library though.
Specify the serialized order of properties
The order of properties during serialization can be defined in Jackson.
Either at class-level specifically using annotation #JsonPropertyOrder.
Or globally for your ObjectMapper using a feature:
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
Example
In your case you can achieve expected order using the annotation on your class:
#JsonPropertyOrder({'id', 'firstName', 'lastName', 'email'})
public class Student {
// body of your class
}
Or separately with an index on your fields:
public class Student {
#JsonProperty(index=10)
private String id;
// not ordered specifically
private String firstName;
private String lastName;
#JsonProperty(index=20)
private String email;
// remainder of your class
}
See also
Jackson ObjectMapper - specify serialization order of object properties
Order of JSON objects using Jackson's ObjectMapper
Jackson JSON - Using #JsonPropertyOrder annotation to define serialized properties ordering

How would I link the two classes together to show the one to many relationship between Person and Address

Address class:
public class Address {
private String country;
private String county;
private String city;
private String postcode;
private String HouseNumber;
public Address(String country, String county, String city, String postcode, String HouseNumber) {
this.country = country;
this.county = county;
this.city = city;
this.postcode = postcode;
this.HouseNumber = HouseNumber;
}
public void view_adress() {
String[] address = {country, county, city, postcode, HouseNumber};
for (int i = 0; i<address.length; i++) {
System.out.println(address[i]);
}
}
public void viewHouseNumber() {
System.out.print(HouseNumber);
}
}
Person class:
public class Person {
private String firstName;
private String lastName;
private String Date_of_birth;
private String PhoneNumber;
private String[] address;
public Person (String firstName, String lastName, String Date_of_birth, String PhoneNumber, String[] address) {
this.firstName = firstName;
this.lastName = lastName;
this.Date_of_birth = Date_of_birth;
this.PhoneNumber = PhoneNumber;
this.address = address;
}
public void view_PhoneNumber() {
System.out.print(PhoneNumber);
}
}
Make use of OOP Composition.
public class Person {
//...
List<Address> addresses;
//...
}
One instance of a Person will have a 0 or more instances of Address.
Note, that in a real world scenario, you better want to retain a list of userIds in your Address class as well, because, more-than-one users, might have one, or also more-than-one addresses, which means, that that your relation must be Many-To-Many.
No less (at all) important thing it to stick with the Java Naming Conventions and name:
classes with PascalCase;
fields and method names with camelCase;
constants with ALL_CAPS_SEPARATED_WITH_UNDERSCORES.

Error upon testing OneToMany relationship to Postman with Spring Boot

#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, unique = true)
private Long id;
private String firstName;
private String lastName;
private String email;
private String password;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "user")
private UserProfile userProfile;
// Hibernate requires a no-arg constructor
public User() {
}
public User(String firstName, String lastName, String email, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
// Getters and Setters (Omitted for brevity)
}
UserProfile
#Entity
#Table(name = "user_profiles")
public class UserProfile implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String phoneNumber;
private String gender;
private String address1;
private String address2;
private String street;
private String city;
private String state;
private String country;
private String zipCode;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", nullable = false)
private User user;
public UserProfile() {
}
public UserProfile(String phoneNumber, String gender,
String address1, String address2, String street, String city,
String state, String country, String zipCode) {
this.phoneNumber = phoneNumber;
this.gender = gender;
this.address1 = address1;
this.address2 = address2;
this.street = street;
this.city = city;
this.state = state;
this.country = country;
this.zipCode = zipCode;
}
// Getters and Setters (Omitted for brevity)
}
My Service
#Component
public class UserService {
#Autowired
UserRepo userRepo;
public ResponseEntity<User> createUser(String firstName, String lastName, String email, String password){
User user=new User(firstName,lastName,email,password);
return new ResponseEntity<>(user,HttpStatus.OK);
}
public ResponseEntity<List<User>> savedataBase(User user){
userRepo.save(user);
return new ResponseEntity<>( userRepo.findAll(), HttpStatus.OK);
}
}
#Component
public class UserPServer {
#Autowired
UserProfileRepo userProfileRepo;
public ResponseEntity<List<UserProfile>> save(UserProfile userProfile){
userProfileRepo.save(userProfile);
return new ResponseEntity<>( userProfileRepo.findAll(), HttpStatus.OK);
}
}
My Controller
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
UserService userService;
#GetMapping("/create/{firsName}/{lastName}/{email}/{password}")
public ResponseEntity<User> create(#PathVariable("firsName") String firstName,
#PathVariable("lastName") String lastName,
#PathVariable("email") String email,
#PathVariable("password") String password){
return userService.createUser(firstName,lastName,email,password);
}
#PostMapping("/usersave")
public ResponseEntity<List<User>> saveDateBase(#RequestBody User users){
return userService.savedataBase(users);
}
}
#RestController
#RequestMapping("/userprofile")
public class UserPConroller {
#Autowired
UserPServer userPServer;
#PostMapping("/userpsave")
public ResponseEntity<List<UserProfile>> savep(UserProfile userProfile){
return userPServer.save(userProfile);
}
}
UserProfile classes like above
I get error like this:
*Column 'user_id' cannot be null
2019-12-26 11:27:35.618 ERROR 6540 --- [nio-8883-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
edit your application.properties file like this
spring.jpa.hibernate.ddl-auto = update
Once you decided who is the "parent" in this relationship you should save the child first with its repository.
Lets assume it is the User.
You would do something like this in your controller
UserProfile newUser = user.getUserProfile();
userProfileRepository.save(newUser);
userRepository.save(user);
This guarantee garantee that the relation is successful.

jackson does not read back data from json when fields are Optional

I am using Java 8 to perform this task. I also following dependency work with JDK8 datatypes.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.6.3</version>
</dependency>
I have a class that looks like
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Optional;
public class Person {
private String firstName;
private String lastName;
private int age;
private Optional<Address> address;
private Optional<String> phone;
private Person() {
}
public Person(String firstName, String lastName, int age) {
this(firstName, lastName, age, Optional.empty(), Optional.empty());
}
public Person(String firstName, String lastName, int age,
Optional<Address> address, Optional<String> phone) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
this.phone = phone;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
#JsonIgnore
public Optional<Address> getAddress() {
return address;
}
#JsonIgnore
public Optional<String> getPhone() {
return phone;
}
#JsonProperty("address")
private Address getAddressForJson(){
return address.orElse(null);
}
#JsonProperty("phone")
private String getPhoneForJson() {
return phone.orElse(null);
}
}
and
public class Address {
private String street;
private String city;
private String state;
private int zip;
private String country;
public Address(String street, String city, String state, int zip, String country) {
this.street = street;
this.city = city;
this.state = state;
this.zip = zip;
this.country = country;
}
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public int getZip() {
return zip;
}
public String getCountry() {
return country;
}
}
I write a test to write a valid Person object to a file and and read it back to a Person object. My test is
#Test
public void writeAndReadPersonAsJsonOnFile() throws Exception {
Address address = new Address("1 Infinite Loop", "Cupertino", "CA", 95014, "USA");
String phone = "1-800-My-Apple";
Person person = new Person("john", "doe", 21, Optional.of(address), Optional.of(phone));
ObjectMapper objectMapper = registerJdkModuleAndGetMapper();
File file = temporaryFolder.newFile("person.json");
objectMapper.writeValue(file, person);
assertTrue(file.exists());
assertTrue(file.length() > 0);
Person personFromFile = objectMapper.readValue(file, Person.class);
assertEquals(person, personFromFile);
}
private ObjectMapper registerJdkModuleAndGetMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
return objectMapper;
}
The file created as part of test has following contents
{
"firstName": "john",
"lastName": "doe",
"age": 21,
"address": {
"street": "1 Infinite Loop",
"city": "Cupertino",
"state": "CA",
"zip": 95014,
"country": "USA"
},
"phone": "1-800-My-Apple"
}
But when reading back, I get personFromFile which looks like following
personFromFile = {Person#1178}
firstName = "john"
lastName = "doe"
age = 21
address = null
phone = null
as you can see, the address and phone they both are null, even though they are present in the file.
What is wrong here?
UPDATE
The codebase is https://github.com/101bits/java8-optional-json. This also contains the failing test
Try marking one of the constructors with #JsonCreator to tell Jackson which constructor to use. Note: this also requires you to mark each of the constructor's parameters with #JsonProperty
You should use the #JsonCreator annotation when you want Jackson to constructor objects with a constructor or factory method as opposed letting Jackson use setters or public (non-final) fields
Additionally, your test will not pass until you override "equals" for both Person and Address
public class Person {
private String firstName;
private String lastName;
private int age;
private Optional<Address> address;
private Optional<String> phone;
public Person(String firstName, String lastName, int age) {
this(firstName, lastName, age, Optional.empty(), Optional.empty());
}
#JsonCreator
public Person(
#JsonProperty("firstName") String firstName,
#JsonProperty("lastName") String lastName,
#JsonProperty("age") int age,
#JsonProperty("address") Optional<Address> address,
#JsonProperty("phone") Optional<String> phone) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
this.phone = phone;
}
Update: Pull Request with passing tests
As far as i have read optional does not get serialized and hence, while deserializing you wont get the value if you are using default java serialization. However, if you are using your serialization, it should be fine.
Refer this link for more details:
Why java.util.Optional is not Serializable, how to serialize the object with such fields

Java dynamic get set methods

Hello I was wondering how I can make the most dynamic get set methods in a java program I am working on? The program has multiple fields and each field needs to have its own get and set method but I want only one get set method that can get and set any field in the class I want.
package kalsi;
public class ContestantInformation {
String firstName, lastName, city, province, postalCode, streetName, streetNumber, phoneNum, birthDate;
public ContestantInformation() {
}
public ContestantInformation(String firstName, String lastName, int streetNumber, String streetName, String city,
String province, String postalCode, int phoneNum, int birthDate) {
this.firstName = firstName;
this.lastName = lastName;
this.birthDate = "" + birthDate;
this.streetNumber = "" + streetNumber;
this.streetName = streetName;
this.city = city;
this.postalCode = postalCode;
this.phoneNum = "" + phoneNum;
}
public void setName(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
You can use your IDE to generate getter/setter methods. If you are using eclipse then you can do it by going to Source>generate methods.
Or alternatively you can use lombok generate getter setter method dynamically. In this case you don't even need to write your getter/setter methods. Look at the example -
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class Person {
#Getter #Setter private String name;
#Getter #Setter private int age = 10;
}

Categories

Resources