I'm designing a DTO that will be serialized to JSON. The serializing framework kept complaining that all the members of my DTO should be public, and that the DTO should have public no-args CTOR.
I was wondering which of these two approaches is better, in your opinion, and why:
1) No getters/setters
public MyClass {
public int someField;
public String someOtherField;
}
2) All getters/setters
public MyClass {
private int someField;
private String someOtherField;
public int getSomeField() {
return someField;
}
public String getSomeOtherField() {
return someOtherField;
}
public void setSomeField(int someField) {
this.someField = someField;
}
public void setSomeOtherField(String someOtherField) {
this.someOtherField = someOtherField;
}
}
Related
We would like to type various properties in Java.
e.g. the e-mail address
But now I get the message all the time:
Could not set field value [test#test.de] value by reflection : [class customer.email] setter of customer.email;
Can not set dataType.EmailAddress field customer.email to java.lang.String
How should I proceed?
#Entity
public class customer {
#Id
#GeneratedValue
private Long id;
private String name;
private EmailAddress email;
}
public class EmailAddress {
public String value;
public EmailAddress(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public boolean setValue(String s) {
this.value = s;
return true;
}
public String mailbox() ...
public String host() ...
public String tld() ...
}
Getter and Setter from HibernateDefaultType not called.
EDIT:
At the end. I want to store a String in the database with the email-Address. In Java I want the EmailAddress Object.
it is much easier. An AttributeConverter make it very easy.
https://thorben-janssen.com/jpa-attribute-converter/
Thank you very much
EDIT:
Here is the Code:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter(autoApply = true)
public class EmailAddressConverter implements AttributeConverter<EmailAddress, String> {
#Override
public String convertToDatabaseColumn(EmailAddress emailAddress) {
return emailAddress.value;
}
#Override
public EmailAddress convertToEntityAttribute(String s) {
return new EmailAddress(s);
}
}
And in the Entity:
#Convert(converter = EmailAddressConverter.class)
private EmailAddress email;
Here is some example of making your own custom type.
public class EmailAddressDescriptor extends AbstractTypeDescriptor<String> {
protected EmailAddressDescriptor() {
super(String.class, new ImmutableMutabilityPlan<>());
}
#Override
public String toString(String value) {
return null;
}
#Override
public String fromString(String string) {
return null;
}
#Override
public <X> X unwrap(String value, Class<X> type, WrapperOptions options) {
return null;
}
#Override
public <X> String wrap(X value, WrapperOptions options) {
return null;
}
#Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
return null;
}
}
Then you would make the Email address class with all your methods
public class EmailAddress extends AbstractSingleColumnStandardBasicType<String> {
private String value;
public EmailAddress() {
super(new VarcharTypeDescriptor(), new EmailAddressDescriptor());
}
#Override
public String getName() {
return "EmailAddress";
}
#Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
return null;
}
}
public String mailbox() ...
public String host() ...
public String tld() ...
How you would use it with your entity will be something like this
#Entity
#TypeDef(name = "emailAddress", typeClass = EmailAddress.class)
public class customer {
#Id
#GeneratedValue
private Long id;
private String name;
#Type (type = "emailAddress")
private EmailAddress emailAddress;
}
Hope this helps
For the below code, my nested parameterized object is always deserialized as LinkedTreeMap instead of the original class
I am using GSON for json serializing & deserializing
Here are the models:
Cart containing wrapped items
public class Cart {
private String id;
private String owner;
private List<ItemWrapper> relatedItems;
.......
public List<ItemWrapper> getRelatedItems() {
return relatedItems;
}
public void setRelatedItems(List<ItemWrapper> relatedItems) {
this.relatedItems = relatedItems;
}
}
Item wrapper
public class ItemWrapper<T> {
private String type;
private String decription;
private T item;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
........
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
Car Item ..
public class Car {
private String model;
private double price;
public String getModel() {
return model;
}
.....
public void setPrice(double price) {
this.price = price;
}
}
Book Item ..
public class Book {
private String name;
private String mediaType;
public String getName() {
return name;
}
.....
public void setMediaType(String mediaType) {
this.mediaType = mediaType;
}
}
When I run the below snippet
Cart cart = gson.fromJson(
"{\"id\":\"id123\",\"owner\":\"Usama\",\"relatedItems\":[{\"type\":\"Book\",\"decription\":\"book item\",\"item\":{\"name\":\"Love\",\"mediaType\":\"pdf\"}},{\"type\":\"Car\",\"decription\":\"car item\",\"item\":{\"model\":\"BMW\",\"price\":500000.0}}]}\n"
+ "",
Cart.class);
System.out.println(cart.getClass().getName());
System.out.println(cart.getRelatedItems().get(0).getItem().getClass().getName());
I got that result
model.Cart
com.google.gson.internal.LinkedTreeMap
instead of
model.Cart
model.Book
Any idea how to fix this.
In my firm we are writing unit tests for code handling Hibernate entities, and we want to decide between:
The "simple" version - Use the entity objects in the unit tests.
The "de-coupled" version - Have the entities implement interfaces, and use mocked objects in unit tests.
Please tell me if you see any actual benefit in using the "de-coupled" version, because otherwise, simplicity wins.
Original code includes an entity for employees:
#Entity
#Table(name="employees")
public class Employee {
// private members ...
#Column(name="id")
public int getId() {
return id;
}
#Column(name="name")
public String getName() {
return name;
}
#ManyToOne(cascade=CascadeType.ALL)
public Department getDepartment() {
return department;
}
// Setter methods ...
}
And an entity for departments:
#Entity
#Table(name="departments")
public class Department {
// private members ...
#Column(name="id")
public int getId() {
return id;
}
#Column(name="name")
public String getName() {
return name;
}
#OneToMany(cascade=CascadeType.ALL)
public Set<Employees> getEmployees() {
return employees;
}
// Setter methods ...
}
Unit test code for the "simple" version:
#Test
public void twoEmployeesWithSameDepartmentAreCoworkers() {
Department finance = new Department();
finance.setId(30);
finance.setName("Finance");
Employee smith = new Employee();
smith.setId(101);
smith.setName("John Smith");
smith.setDepartment(finance);
Employee banks = new Employee();
smith.setId(102);
smith.setName("Merry Banks");
smith.setDepartment(finance);
boolean expectedResult = true;
boolean result = employeeService.areEmployeesCoworkers(smith, banks);
assertEquals(expectedResult, result);
}
In the "de-coupled" version, some changes should be made and the entities look like this:
Two new interfaces:
public interace IEmployee {
public int getId();
public String getName();
public IDepartment getIDepartment();
}
public interace IDepartment {
public int getId();
public String getName();
public Set<IEmployee> getIEmployees();
}
Entity Employee now implements IEmployee:
public class Employee implements IEmployee {
// private members ...
#Column(name="id")
#Override
public int getId() {
return id;
}
#Column(name="name")
#Override
public String getName() {
return name;
}
#ManyToOne(cascade=CascadeType.ALL)
public Department getDepartment() {
return department;
}
#Override
public IDepartment getIDepartment() {
return getDepartment();
}
// Setter methods ...
}
And entity Department now implements IDepartment:
public class Department implements IDepartment {
// private members ...
#Column(name="id")
#Override
public int getId() {
return id;
}
#Column(name="name")
#Override
public String getName() {
return name;
}
#OneToMany(cascade=CascadeType.ALL)
public Set<Employees> getEmployees() {
return employees;
}
#Override
public Set<IEmployees> getIEmployees() {
Set<IEmployees> iemployees = new HashSet<IEmployees>();
iemployees.addAll(getEmployees());
return iemployees;
}
// Setter methods ...
}
Unit test code for the "loosely coupled" version:
#Test
public void twoEmployeesWithSameDepartmentAreCoworkers() {
Set<IEmployee> financeMockedEmployees = new HashSet<IEmployee>();
IDepartment mockedFinance = new IDepartment() {
public int getId() {
return 30;
}
public String getName() {
return "Finance";
}
public Set<IEmployee> getIEmployees() {
return financeMockedEmployees;
}
};
IEmployee mockedSmith = new IEmployee() {
public int getId() {
return 101;
}
public String getName() {
return "John Smith";
}
public IDepartment getIDepartment() {
return mockedFinance;
}
};
IEmployee mockedBanks = new IEmployee() {
public int getId() {
return 102;
}
public String getName() {
return "Merry Banks";
}
public IDepartment getIDepartment() {
return mockedFinance;
}
};
financeMockedEmployees.add(mockedSmith);
financeMockedEmployees.add(mockedBanks);
boolean expectedResult = true;
boolean result = employeeService.areEmployeesCoworkers(mockedSmith, mockedBanks);
assertEquals(expectedResult, result);
}
Note that areEmployeesCoworkers method was first:
public boolean areEmployeesCoworkers(Employee emp1, Employee emp2)
And is now:
public boolean areEmployeesCoworkers(IEmployee emp1, IEmployee emp2)
1) Introducing an interface for testability purpose may make sense for final classes as you cannot mock them in a conventional way.
It is really not your context.
2) Which is the advantage to put an interface in front of the data model class ? You will not have multiple implementation of accessing/setting data methods.
So the introduction of interface for JPA/Hibernate entities have zero added value.
It complicates the application code of an already testable code.
Creating anonymous classes for fixtures as in your example makes the test code also more complex.
Hi I have a question regarding Bean Validation (JSR-303). We can validate one bean against set of annotations provided in a bean. What if i have a Bean Car which extends Bean Vehicle, and if i pass Bean Car to the validator, how to make Bean Vehicle(i.e. Super Class) also get Validated ?
I am using this Bean Validation in Camel. Below is my Code
public void configure() throws Exception {
from("file:data/source?noop=true").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Process 1");
Car car = new Car();
//this property is of Super Class
//car.setVehicleId(1);
car.setName("Swift");
car.setCompany("Maruti");
exchange.getIn().setBody(car);
}
}).to("bean-validator://v").process(new Processor() {
#Override
public void process(Exchange arg0) throws Exception {
System.out.println("Exchange is : "+arg0.getIn().getBody(Car.class));
}
});
}
My Car Bean is
public class Car extends Vehicle{
#NotNull
private String name;
#NotNull
private String company;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
My Vehicle Bean is
public class Vehicle {
#NotNull
private int vehicleId;
public int getVehicleId() {
return vehicleId;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
}
Thank you. Help will be greatly appreciated.
I got this working. The problem is i have used primitive types in Vehicle [ private int vehicleId; ]
So i corrected it with [ private Integer vehicleId; ]. So after this my Vehicle bean is
public class Vehicle {
#NotNull
private Integer vehicleId;
public Integer getVehicleId() {
return vehicleId;
}
public void setVehicleId(Integer vehicleId) {
this.vehicleId = vehicleId;
}
}
I have following json data
{"id":10606,
"name":"ProgrammerTitle",
"objectMap":{"programme-title":"TestProgramme","working-title":"TestProgramme"}
}
I want to set this data to my pojo object
public class TestObject {
private Long id;
private String name;
#JsonProperty("programme-title")
private String programmeTitle;
#JsonProperty("working-title")
private String workingTitle;
}
Here i am able to set id and name in my test object but for object map i am not able to set data.
So i have made on more class for ObjectMap which contains programmeTitle & workingTitle this works fine but i can't set this fields directly to my pojo object
is this possible to set?
I am using Jackson Object Mapper to convert json data.
It is working fine if i create another java object inside my pojo like:
public class TestObject {
private Long id;
private String name;
#JsonProperty("objectMap")
private ObjectMap objectMap;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ObjectMap getObjectMap() {
return objectMap;
}
public void setObjectMap(ObjectMap objectMap) {
this.objectMap = objectMap;
}
}
public class ObjectMap {
#JsonProperty("programme-title")
private String programmeTitle;
#JsonProperty("working-title")
private String workingTitle;
public String getProgrammeTitle() {
return programmeTitle;
}
public void setProgrammeTitle(String programmeTitle) {
this.programmeTitle = programmeTitle;
}
public String getWorkingTitle() {
return workingTitle;
}
public void setWorkingTitle(String workingTitle) {
this.workingTitle = workingTitle;
}
}
If your JSON is like this
{"id":10606,
"name":"ProgrammerTitle",
"objectMap":{"programme-title":"TestProgramme","working-title":"TestProgramme"}
}
then you may write your object mapper class like this..
public class Program{
public static class ObjectMap{
private String programme_title, working_title;
public String getprogramme_title() { return programme_title; }
public String getworking_title() { return working_title; }
public void setprogramme_title(String s) { programme_title= s; }
public void setworking_title(String s) { working_title= s; }
}
private ObjectMap objMap;
private String name;
public ObjectMap getobjectMap () { return objMap; }
public void setObjectMap (ObjectMap n) { objMap= n; }
private Long id;
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
private String name;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
please refer this check it
You can write your own deserializer for this class:
class EntityJsonDeserializer extends JsonDeserializer<Entity> {
#Override
public Entity deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Root root = jp.readValueAs(Root.class);
Entity entity = new Entity();
entity.setId(root.id);
entity.setName(root.name);
if (root.objectMap != null) {
entity.setProgrammeTitle(root.objectMap.programmeTitle);
entity.setWorkingTitle(root.objectMap.workingTitle);
}
return entity;
}
private static class Root {
public Long id;
public String name;
public Title objectMap;
}
private static class Title {
#JsonProperty("programme-title")
public String programmeTitle;
#JsonProperty("working-title")
public String workingTitle;
}
}
Your entity:
#JsonDeserialize(using = EntityJsonDeserializer.class)
class Entity {
private Long id;
private String name;
private String programmeTitle;
private String workingTitle;
//getters, setters, toString
}
And usage example:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class JacksonProgram {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Entity entity = mapper.readValue(jsonString, Entity.class);
System.out.println(entity);
}
}
Above program prints:
Entity [id=10606, name=ProgrammerTitle, programmeTitle=TestProgramme, workingTitle=TestProgramme]