What is the best solution for creating POJO, at controller level or method level.
For example I have EmployeeController which contains below methods.
getAllEmployees()
addEmployee(AddEmployeeRequest employee)
updateEmployee(UpdateEmployeeRequest employee)
removeEmployee(RemoveEmployeeRequest employee)
//Method level classes
public class AddEmployeeRequest
{
private String name;
private Date dateOfBirth;
private String Address;
}
public class UpdateEmployeeRequest
{
private long id;
private String Address;
}
public class RemoveEmployeeRequest
{
private long id;
}
or
getAllEmployees()
addEmployee(EmployeeRequest employee)
updateEmployee(EmployeeRequest employee)
removeEmployee(EmployeeRequest employee)
//Controller level class
public class EmployeeRequest
{
private long id;
private String name;
private Date dateOfBirth;
private String Address;
}
If I have method level models then do I have to create the respective sevice level DTO models also ?
In fact, if you are using spring, it is neccessary to use a single POJO because spring use reflection for accessing the ClassName, DeclaredFields etc. Using multiple POJO will be annoying for Spring.
See here some more details about reflection: https://crunchify.com/create-simple-pojo-and-multiple-java-reflection-examples/
Related
I am new spring boot developer and i am trying to develope and rest api . when I do it ,I get and issues that my api return two duplicated response in postman .But i haven't code anythiong to get duplicated valuese in my code . the one of duplicate values is my model clase variable and athor one is table's attribute name .
below response in postman
model class
public class person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
private Long id;
#Column(name = "name")
private String Name ;
#Column(name ="surname")
private String Surname;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getSurname() {
return Surname;
}
public void setSurname(String surname) {
Surname = surname;
}
}
repository
#Repository
public interface personRepository extends JpaRepository<person,Long> {
}
controller
#RestController
#RequestMapping("/person")
public class personController {
#Autowired
private personRepository repository;
public personController(personRepository repository) {
this.repository = repository;
}
#GetMapping("/view/list/person")
private List<person> viewperson() {
return repository.findAll();
}
#PostMapping("/insert/person")
private person savePerson(#RequestBody person obj) {
return repository.save(obj);
}
#DeleteMapping("/delete/{id}")
private void delete(#PathVariable Long id) {
repository.deleteById(id);
}
}
application.properties
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialec
t
The problem is that you're not following the proper conventions in your naming strategy.
Due to this, Jackson doesn't know that your getters (getSurname(), getName()) are referencing the fields Surname and Name. That's why it serializes both your fields and your getters separately to JSON.
To fix this, you can follow the Java naming conventions and use a lowercase letter for the first character of your fields.
For example:
#Column(name = "name")
private String name; // Change this
#Column(name ="surname")
private String surname; // Change this
This will change your JSON output to:
{
"id": 1,
"name": "bryan",
"surname": "Nicky"
}
If you want to keep your JSON with capital letters, you can use the #JsonProperty annotation:
#JsonProperty("Name") // Add this
#Column(name = "name")
private String name;
#JsonProperty("Surname") // Add this
#Column(name ="surname")
private String surname;
Unrelated to your question, but according to those naming conventions, your classes should start with a capital (eg. Person, PersonController, PersonRepository, ...).
In the code below, class Address is nested in Entity User. I wonder if all the attributes of Address are private, do we need getter and setter for each of the field in Address? Notice there is a List<String>, so I'm not sure if Room will work well with #TypeConverter in this case.
public class Address {
public String street;
public String state;
public List<String> city;
#ColumnInfo(name = "post_code")
public int postCode;
}
#Entity
public class User {
#PrimaryKey
public int id;
public String firstName;
#Embedded
public Address address;
}
You can easily add getter/setters with #Ignore annotation and the converter will ignore these methods.
#Ignore
public List<String> getCity() {
return city;
}
You can refer here
Create the entity
I using Orika mapper to map two beans. i would like to exclude billingSummary.billableItems property while mapping. I am trying below option but it is not working.
Any help?
public class Cart {
private String id;
private String name;
private BillingSummary billingSummary;
private String address;
//with getter and setter methods
}
public class BillingSummary {
private String billingItem;
private String billingItemId;
private BillableItems billableItems;
...
// with getter setter methods
}
//FilteredCart is same as Cart.
public class FilteredCart {
private String id;
private String name;
private BillingSummary billingSummary;
private String address;
//with getter and setter methods
}
#Component
public class CartMapper extends ConfigurableMapper {
#Override
public void configure(MapperFactory mapperFactory) {
mapperFactory.classMap(Cart.class,FilteredCart.class).exclude("billingSummary.billableItems").byDefault().register();
}
}
What you can do is adding another mapping to the mapperFactory in order to define how you want to map the BillingSummary to itself. In this way, when mapping from Cart to FilteredCart, you can configure to exclude to map the billableItems.
Therefore, your CartMapper will look like this:
#Component
public class CartMapper extends ConfigurableMapper {
#Override
public void configure(MapperFactory mapperFactory) {
mapperFactory.classMap(BillingSummary.class, BillingSummary.class).exclude("billableItems").byDefault().register();
mapperFactory.classMap(Cart.class,FilteredCart.class).byDefault().register();
}
}
I have class:
class TestClass {
#Id
private ObjectId id;
private ObjectId parentId;
private String name;
private String describe;
private String privateData;
public TestClass(ObjectId parentId, String name, String describe, String privateData) {
this.parrentId = parrentId;
this.name = name;
this.describe = describe;
this.privateDate = privateData;
}
// get/set methods...
}
Can I use this class in MongoRepository and #RequestBody? Is it safe? parrentId and privateData is private properties and RequestBody does not have to fill them.
mongorepository:
public interface TestClassRepository extends MongoRepository<TestClass, String> {
public TestClass findById(ObjectId id);
}
post method:
#RequestMapping(value="/testclass", method=RequestMethod.POST)
public void create(#RequestBody TestClass testClass) {
testClass.setParentId(...);
repo.insert(testClass);
}
For example:
{"name": "test", "describe": "test", "id": "54d5261a8314fe3c650d5b1d", "parentId": "54d5261a8314fe3c650d5b1d", "privateData": "WrongPrivateData"}
How can I do that it was impossible to set properties id, parentId, privateDate?
Or need I create new class for RequestBody? I don't want duplicate code.
It should be better and safe to use separate models for DAO and VO layers(view). If your models currently looks the same, it doesn't mean that they will stay the same in future. You can use the Dozer Mapping framework for mappings between your models. It's easy,fast and safe.
If you need to skip some field from mongotemplate mapping use #Transient annotation.
P.S. You don't need findById method, because mongotemplate already have find method which uses key as param. TestClass should have an empty constructor.
Can you not validate static inner classes using hibernate validation? I have the following form:
public class Thing {
#NotNull // WORKS!
private String message;
private someClass obj1;
private someOtherClass obj2;
public static class someClass
{
#NotNull //DOES NOT WORK
private String someField;
}
public static class someOtherClass
{
#NotNull //Does NOT WORK
private String someOtherField;
}
}
I got it, you need to mark #Valid on the instances of the someClass and someOtherClass. This fixed the issue for me. Looks like the #Valid annotation I had on my controller for my Thing object wasn't applying recursively to the state of its nested objects.
You can use #Valid on the address property in a combination of other constraints inside Address class. A valid example would be:
public class Person {
#NotEmpty
private String fullName;
#Email
private String email;
#Pattern (regexp = "[0-9]+")
private String telNo;
#NotNull
#Valid
private Address address;
}
class Address {
#NotEmpty
private String houseNumber;
#NotEmpty
private String streetName;
private String province;
private String country;
}