I am using Jackson to save my java object (Person.class) as a json file and load from it using jackson as well.
This is what I am saving at the moment:
public class Person {
private String name;
private int yearOfBirth;
public Person(String name, int yearOfBirth) {
this.name = name;
this.yearOfBirth = yearOfBirth;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getYearOfBirth() {
return yearOfBirth
}
public void setYearOfBirth(int yearOfBirth) {
this.yearOfBirth = yearOfBirth;
}
}
Even though a person's name (in this case) CANNOT be changed, nor can their year of birth, I have to have the getters and setters for Jackson to recognise the values otherwise it will give an exception:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "name"
How can i make my fields name and yearOfBirth (without making them PUBLIC ofcourse) final fields uneditable after initialisation.
This is my saving and loading using jackson:
saving:
public void savePerson(File f, Person cache) {
ObjectMapper saveMapper = new ObjectMapper()
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
saveMapper.setVisibilityChecker(
saveMapper.getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.NONE).
withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
);
ObjectWriter writer = saveMapper.writer().withDefaultPrettyPrinter();
writer.writeValue(f, cache);
}
loading:
public Person load(File f) {
return new ObjectMapper().readValue(f, Person.class);
}
User #JsonProperty and it will work.
import com.fasterxml.jackson.annotation.JsonProperty;
public class Person {
private final String name;
private final int yearOfBirth;
public Person(#JsonProperty("name") String name, #JsonProperty("yearOfBirth") int yearOfBirth) {
this.name = name;
this.yearOfBirth = yearOfBirth;
}
public String getName() {
return name;
}
public int getYearOfBirth() {
return yearOfBirth;
}
}
Related
I have the following class that is created with the usage of a builder:
public class Foo {
private String name;
private int age;
public String getName() { return name; }
public int getAge() { return age; }
private Foo(Builder b) {
name = b.name;
age = b.age;
}
public static final class Builder {
private String name;
private int age;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
}
}
Now I want to add a JUnit test for this where if this class were to change (via new field were to be added, some other changes made to this) that would also be reflected once the class got serialized, I want that test to fail to catch that change. I am not aware of any libraries that can do this, how can this be done?
I'm new to java reflexion and I'm trying to integrate SQLite with java.
I have 2 objects Person and Department. There is relation OneToMany between them.
As I'm working on save functionality (SQLite) I want to extract field names and its values so I can build full query. I have no problem with extracting names and values of fields that are of primitive type (String, int etc.). I have problem with type of Object (in this case it is Department field in Person object).
I'm able to print object but unable to access its fields (namely pk).
Could you help me please?
METHOD FOR EXTRACTING FIELDS
// method for extracting fields
private StringBuilder getFieldsWithValues(Object entity) throws IllegalAccessException, NoSuchFieldException {
StringBuilder query = new StringBuilder();
for (Field field : entity.getClass().getDeclaredFields()) {
System.out.print((field.getName() + " - "));
field.setAccessible(true);
// TODO: eliminate if statement from for cycle
if (field.isAnnotationPresent(ManyToOne.class)) {
// HERE I want to extract the pk value from Department object
System.out.println(field.get(entity));
} else {
System.out.println(field.get(entity));
}
}
return query;
}
DEPARTMENT OBJECT
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Department {
#Id
private long pk;
private String name;
private String code;
public Department() {
}
public Department(String name, String code) {
this.name = name;
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String toString() {
return String.format("Department %d: %s (%s)", pk, name, code);
}
}
PERSON OBJECT
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity
public class Person {
#Id
private long id;
private String surname;
private String name;
private int age;
#ManyToOne
private Department department;
public Person(String surname, String name, int age) {
this.surname = surname;
this.name = name;
this.age = age;
}
public Person() {
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long getId() {
return id;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
#Override
public String toString() {
return String.format("Person %d: %s %s (%d)", id, surname, name, age);
}
}
I have the JSON looks like the following:
{
"name":"John",
"n_age":500
}
and I have a class Person:
public class Person {
private final String name;
private final int age;
#JsonCreator
public Person(#JsonProperty("name") String name) {
this.name = name;
this.age = 100;
}
public String getName() {
return name;
}
#JsonGetter("n_age")
public int getAge() {
return age;
}
}
I need to deserialize and serialize it, but when I'm trying to deserialize this JSON I get unexpected result.
public static void main(String... args) {
ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue(args[0], Person.class);
System.out.println(person.getAge()); // I got 500, but I expect 100.
}
Why when I'm trying to deserialize it the #JsonGetter annotation is used for it?
How can I disable #JsonGetter annotation when I try to deserialize the JSON?
If #JsonGetter is used as is currently, it will map property n_age to field age. To citate the docs - It can be used as an alternative to more general JsonProperty annotation (which is the recommended choice in general case).
To fix this behaviour, you need to:
Tell jackson to ignore property n_age, otherwise you will get exception for unrecognized property not marked as ignorable - #JsonIgnoreProperties("n_age").
Tell jackson to allow getters for ignored properties(basically make it readonly) - #JsonIgnoreProperties(value = {"n_age"}, allowGetters = true)
In the end, Person should look like this:
#JsonIgnoreProperties(value = {"n_age"}, allowGetters = true)
public class Person {
private final String name;
private final int age;
#JsonCreator
public Person(#JsonProperty("name") String name) {
this.name = name;
this.age = 100;
}
public String getName() {
return name;
}
#JsonGetter("n_age")
public int getAge() {
return age;
}
#Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
I found the solution for fixing my issue, maybe it's a bad way, but it works for me as well. I'm ignoring the n_age property during deserialization and allowing getters during serialization.
Thanks a lot #Chaosfire for the help!
#JsonIgnoreProperties({"n_age"}, allowGetters = true)
public class Person {
private final String name;
private final int age;
#JsonCreator
public Person(#JsonProperty("name") String name) {
this.name = name;
this.age = 100;
}
public String getName() {
return name;
}
#JsonGetter("n_age")
public int getAge() {
return age;
}
}
I have a User class and a Pet class. A user can have multiple pets.
I'm trying to retreive a user document and convert it to a user object as follows:
loggedInUser = documentSnapshot.toObject(User.class);
It throws the following exception:
java.lang.RuntimeException: Could not deserialize object. Can't convert object of type com.google.firebase.firestore.DocumentReference to type com.example.pawsibilities.Pet (found in field 'pets.[0]')
Here is an example of a user in firestore. One of its fields is an array of references (pets).
My pet class look like this in Firestore, and it looks like this in Java:
public class Pet {
private String name;
private String type;
private LocalDate birthday;
private String breed;
public enum Gender {
Female,
Male,
Unknown
}
private Gender gender;
private boolean neutered;
private float height;
private float weight;
private String healthNotes;
private boolean lostStatus = false;
private LocalDate lostSince = null;
private ArrayList<LastSeenDetails> lastSeenDetailsList = null;
public Pet() { }
public Pet(String name, String type, LocalDate birthday, String breed, Gender gender, Boolean neutered, float height, float weight, String healthNotes) {
this.name = name;
this.type = type;
this.birthday = birthday;
this.breed = breed;
this.gender = gender;
this.neutered = neutered;
this.height = height;
this.weight = weight;
this.healthNotes = healthNotes;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getBirthday() {
return birthday.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
}
public String getLostSince() {
return lostSince.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
}
public String getBreed() {
return breed;
}
public String getGender() {
return gender.name();
}
public String getHeight() {
return height + " cm";
}
public String getWeight() {
return weight + " kg";
}
public String getHealthNotes() {
return healthNotes;
}
public ArrayList<LastSeenDetails> getLastSeenDetailsList() {
return lastSeenDetailsList;
}
public boolean isLost(){ return lostStatus; }
public String isNeutered() {
if (neutered == true) {
return "Yes";
} else
return "No";
}
public void setLostStatus(boolean lostStatus) {
this.lostStatus = lostStatus;
}
public void setLostSince(LocalDate time) { this.lostSince = time; }
public void setLastSeenDetailsList(ArrayList<LastSeenDetails> lastSeenDetailsList) {
this.lastSeenDetailsList = lastSeenDetailsList;
}
}
It has an empty constructor and all fields have a getter method. I can't seem to find the issue...
It's not necessary to convert document to User, as the retrieved document is an object of type User.
Try this,
User user = documentSnapshot.getData();
or
User user = documentSnapshot.get(String field);
This question already has answers here:
Why is each public class in a separate file?
(11 answers)
Closed 3 years ago.
I am using Eclipse to run this code program to test a Person class and its subclasses. In Eclipse it shows there are errors--that each child class must be defined in its own file.
I am learning Java, and would like to know if this is a must? Or can I make it work with parent and child classes all in one file? If I'm missing something, please point me in the right direction. Thank you!
Here is my code: [I put this is all in one file on Eclipse]
import java.util.*;
//Test program to test Person class and its subclasses
public class Test {
public static void main(String[] args) {
Person person = new Person("person");
Student student = new Student ("student");
Employee employee = new Employee("employee");
Faculty faculty = new Faculty("faculty");
Staff staff = new Staff("staff");
//invoke toString() methods
System.out.println(person.toString());
System.out.println(student.toString());
System.out.println(employee.toString());
System.out.println(faculty.toString());
System.out.println(staff.toString());
}
}
//Defining class Person
public class Person {
protected String name;
protected String address;
protected String phoneNum;
protected String email;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress () {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public String getEmail() {
return email;
}
public void setEmail (String email) {
this.email = email;
}
#Override
public String toString() {
return "Name:"+getName()+"Class:"+this.getClass().getName();
}
}
//Defines class Student extends Person
public class Student extends Person {
public static final String FRESHMAN = "freshman";
public static final String SOPHMORE = "sophmore";
public static final String JUNIOR = "junior";
public static final String SENIOR = "senior";
protected String classStatus;
public Student(String name) {
super(name);
}
public Student(String name, String classStatus) {
super(name);
this.classStatus = classStatus;
}
#Override
public String toString() {
return "Name:"+getName()+"Class:"+this.getClass().getName();
}
}
//Defines class Employee extends Person
public class Employee extends Person {
protected double salary;
protected String office;
protected MyDate dateHired;
public Employee(String name) {
this(name, 0, "none", new MyDate());
}
public Employee(String name, double salary, String office, MyDate dateHired) {
super(name);
this.salary = salary;
this.office = office;
this.dateHired - dateHired;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getOffice() {
return office;
}
public void setOffice (String office) {
this.office = office;
}
public MyDate getDateHired() {
return dateHired;
}
public void setDateHired(MyDate dateHired) {
this.dateHired = dateHired;
}
#Override
public String toString() {
return "Name:"+getName()+"Class:" + this.getClass().getName();
}
}
//Defines class Faculty extends Employee
public class Faculty extends Employee {
public static String LECTURER = "lecturer";
public static String ASSISTANT_PROFESSOR = "assistant professor";
public static String ASSOCIATE_PROFESSOR + "associate professor";
public static PROFESSOR = "professor";
protected String officeHours;
protected String rank;
public Faculty(String name) {
this(name, "9-5 PM", "Employee");
}
public Faculty(String name, String officeHours, String rank) {
super(name);
this.officeHours = officeHours;
this.rank = rank;
}
public String getOfficeHours() {
return officeHours;
}
public void setOfficeHours(String officeHours) {
this.officeHours = officeHours;
}
public String getRank() {
return rank;
}
public void setRank(String rank) {
this.rank=rank;
}
#Override
public String toString() {
return "Name:"+getName()+"Class:"+this.getClass().getName();
}
}
//Defines class Staff extends Employee
public class Staff extends Employee {
protected String title;
public Staff(String name) {
this(name, "none");
}
public Staff(String name, String title) {
super(name);
this.title=title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public String toString() {
return "Name:"+getName()+"Class:"+this.getClass().getName();
}
}
//Define class MyDate
public class MyDate {
private int month, day, year;
public MyDate (int month, int day, int year) {
this.day=day;
this.month=month;
this.year=year;
}
}
Yes, there should be one class per file. Moreover, you are using the MyDate class in the Employee class, which you need to extend and you cannot extends more than one class, so it's better use the predefined Date class which is present java.util.Date. Import this in the Employee class.
import java.util.Date;
instead of this:
public Employee(String name, double salary, String office, MyDate dateHired)
use:
public Employee(String name, double salary, String office, Date dateHired)
There are some careless mistakes:
in Employee class
public static String ASSOCIATE_PROFESSOR + "associate professor";
change to:
public static String ASSOCIATE_PROFESSOR = "associate professor";
Similarly in faculty class
public static String ASSOCIATE_PROFESSOR + "associate professor";
put = instead of +.
Now this code will work.
Yes it is a must. One class per file. Class can have inner classes. You can define subclasses as inner classes. But I recommend putting them in separate files and don't use inner classes.