Modelmapper circular mapping - modelmapper

I've parent and child class with respective DTO's as follows
class Parent {
List<Child> children;
// setters and getters
}
class Child {
Parent parent;
}
class ParentDto {
List<ChildDto> children;
// setters and getters
}
class ChildDto {
ParentDto parent;
// setters and getters
}
When I try to map Parent to ParentDto I'm getting StackOverflowError.
Please help me in resolving the issue.

I know this post is old but I will try to give one answer in case someone from google to arrived here.
Probably you have a dynamic object creation.
Recently I had a problem like this. In my case I have a class Student that extends Person. And Person has three others attributes of type Person: father, mother and responsible. In case, I had a circularity relationship. When I ran my JUnits tests I got a circularity calls. I did't get a stakOverflow because the Spring (after some time) closes the data base connections.
I resolved this problem removing the dynamics objects creations from my Person class.
Another approach to solve this problem is adding a Condition in your mapper. You can read more about conditions here. For example, you can have some Conditions saying: "If the person attribute id is 10, then, doesn't need map it.". This way we can avoid infinity mapping.
Well, let's see some snippeds of code:
Student class:
public class Student extends Person implements IStudent {
private Person financialResponsible;
// Getters and setters.
}
Person class:
public class Person implements IPerson {
private Long id;
private String name;
private Person father;
private Person mother;
private Person responsible;
private Address address;
// Getters and setters.
// This is my real problem. I removed it and the mapper worked.
public IPerson getFather() {
if (father == null) father = new Person();
return father;
}
}
StudentDTO class:
public class StudentDTO extends PersonDTO {
private PersonDTO financialResponsible;
// Getters and setters.
}
PersonDTO class:
public class PersonDTO {
private Long id;
private String name;
private PersonDTO father;
private PersonDTO mother;
private PersonDTO responsible;
private AddressDTO address;
// Getters and setters.
}
Here is a example of conditions:
...
import org.modelmapper.Condition;
...
ModelMapper mapper = new ModelMapper();
// Define STRICT to give high precision on mapper.
mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
/*
* Create conditions to avoid infinity circularity.
*/
// Condidions.
final Condition<IStudent, StudentDTO> fatherIsTen = mappingContext -> mappingContext.getSource().getFather().getId() == 10;
final Condition<IStudent, StudentDTO> motherIsTen = mappingContext -> mappingContext.getSource().getMother().getId() == 10;
final Condition<IStudent, StudentDTO> resposibleIsTen = mappingContext -> mappingContext.getSource().getResponsible().getId() == 10;
// Adding conditions on mapper.
mapper.createTypeMap(IStudent.class, StudentDTO.class) //
.addMappings(mapper -> mapper.when(fatherIsTen).skip(StudentDTO::setFather))
.addMappings(mapper -> mapper.when(motherIsTen).skip(StudentDTO::setMother))
.addMappings(mapper -> mapper.when(resposibleIsTen).skip(StudentDTO::setResponsible));
I hope help o/

Related

JHipster EntityMapper interface (mapstruct): map a Spring projection interface

I've generated a new project with JHipster v4.6.0 generator and I'm using its EntityMapper interface to do the mapping between domain and DTO objects.
public interface EntityMapper <D, E> {
public E toEntity(D dto);
public D toDto(E entity);
public List <E> toEntity(List<D> dtoList);
public List <D> toDto(List<E> entityList);
}
I need to use the Spring projection to have a smaller domain and DTO objects, (I don't want all fields of the entity), so I've created an interface with only the getters of the fields I need, and I've created a method in the repository which retrive this interface type (following the Spring reference guide)
public interface ClienteIdENome {
Long getId();
String getNome();
}
#Repository
public interface ClienteRepository extends JpaRepository<Cliente,Long> {
ClienteIdENome findById(Long id);
}
The query findById retrieve a ClienteIdENome object with only id and nome fields.
Now, I would like to map this object in the following DTO:
public class ClienteIdENomeDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
#NotNull
#Size(max = 50)
private String nome;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
So, I created the mapper interface:
#Mapper(componentModel = "spring", uses = {})
public interface ClienteIdENomeMapper extends EntityMapper<ClienteIdENomeDTO, ClienteIdENome> {
}
But Eclipse report to me an error in the EntityMapper interface for the method "public E toEntity(D dto)" with the message:
No implementation type is registered for return type it.andrea.ztest01.repository.ClienteIdENome.
Any help?
Thanks a lot
Your ClienteIdENome is not really an entity. I would argue that you don't need to use the EntityMapper, but you need to define a one way mapper. From ClienteIdENome to ClienteIdENomeDTO.
Your mapper needs to look like:
public interface ClienteIdENomeMapper {
ClienteIdENomeDTO toDto(ClienteIdENome entity);
List <ClienteIdENomeDTO> toDto(List<ClienteIdENome> entityList);
}
I don't know JHipster, so I can't say what will mean using a mapper different than EntityMapper.

How to override JAXB #XMLAccessorType(XMLAccessType.FIELD) specified at a Class level with #XMLElement on a getter method for a property?

In the example code below, Employee class has been specified with JAXB field level access type. For the property dept, however, the access type has been specified at getter method level with #XMLElement annotation.
During marshalling of Organization class, the following exception is thrown -
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "dept"
this problem is related to the following location:
at public java.lang.String com.playground.jaxb.Employee.getDept()
this problem is related to the following location:
at private java.lang.String com.playground.jaxb.Employee.dept
Can you help me understand why this overriding of JAXB accessor type is not working please? Also any solution would be highly appreciated.
Example
Root Element Class
package com.playground.jaxb;
#XMLRootElement(name="organization")
public class Organization {
#XmlElementWrapper(name = "employees")
#XmlElement(name = "employee")
private Set<Employee> employees;
public Organization{}
// Remainder omitted...
}
Employee Class
package com.playground.jaxb;
#XMLAccessorType(XMLAccessType.FIELD)
public class Employee {
private String name;
private String dept;
#XMLElement(name="department")
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
public Employee {}
// Remainder omitted...
}
You can re-name getter/setter pair, e.g. getDept() -> getDepartment()
private String dept;
#XmlElement(name="department")
public String getDeptartment() {
return dept;
}
public void setDeptartment(String dept) {
this.dept = dept;
}
but in this case you will have duplicate in XML
<dept>my_dept</dept>
<department>my_dept</department>
Or you can annotate field dept with #XmlTransient annotation, if you want to change access type it.
#XmlTransient
private String dept;
#XmlElement(name="department")
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
In this case, dept field will be ignored and getter/setter pair will be used instead

How do I access a derived class value from a base class static method?

Here is a sample of what I am trying to accomplish:
public class BaseClass<T>
{
public static T GetByID(int ID)
{
// Need database name here that is determined at design time in the derived class.
var databaseName = "";
// do some stuff involving database name that gets me object by ID here.
return default(T);
}
}
public class DerivedClass : BaseClass<DerivedClass>
{
private string DatabaseName { get; set; }
}
Basically, how would I access the derived "DatabaseName" in the base class static GetByID method?
EDIT: After I posted this, I tried one more thing. I played with attributes earlier, and failed, but I think my brain was mushy. Just tried again and ran a test, and it is working. Here is the updated sample.
public class BaseClass<T>
{
public static T GetByID(int ID)
{
// Need database name here that is determined at design time in the derived class.
var databaseName = ((DatabaseAttribute)typeof(T).GetCustomAttributes(typeof(DatabaseAttribute), true).First()).DatabaseName;
// do some stuff involving database name that gets me object by ID here.
return default(T);
}
}
[Database("MyDatabase")]
public class DerivedClass : BaseClass<DerivedClass>
{
}
public class DatabaseAttribute : Attribute
{
public DatabaseAttribute(string databaseName)
{
DatabaseName = databaseName;
}
public string DatabaseName { get; set; }
}
Base class to derived class is a one-way inheritance: The base class has no knowledge of the existance of a derived class, and so it can't access it.
In addition to that you will have a hard time accessing a non-static property from a static method.
I know you've already answered your own question, but some improvements....
Add a where clause to guarantee inheritance, it means any static methods can make use of inherited methods. You might also want to add the new() clause if you wish to be able to create instances of the inherited class.
public class BaseClass<T> : where T : BaseClass<T>
{
static readonly string databaseName;
static BaseClass() {
// Setup database name once per type of T by putting the initialization in
// the static constructor
databaseName = typeof(T).GetCustomAttributes(typeof(DatabaseAttribute),true)
.OfType<DatabaseAttribute>()
.Select(x => x.Name)
.FirstOrDefault();
}
public static T GetByID(int ID)
{
// Database name will be in the static field databaseName, which is unique
// to each type of T
// do some stuff involving database name that gets me object by ID here.
return default(T);
}
}
[Database("MyDatabase")]
public class DerivedClass : BaseClass<DerivedClass>
{
}
public class DatabaseAttribute : Attribute
{
public DatabaseAttribute(string databaseName)
{
DatabaseName = databaseName;
}
public string DatabaseName { get; set; }
}

How to Inject ManagedBeans in JSF2.0

I have got Controller-ManagedBeans and Model-ManagedBeans (like MVC-Pattern).
Here my Controller:
#ManagedBean
#RequestScoped
public class ProjectController {
private ProjectData projectBean; //The Model-ManagedBean (see below)!
private IProjectService projectService; //My Service-Layer
public ProjectController(){
init();
}
private void init(){
projectBean = new ProjectData();
projectService = new ProjectService();
}
public String saveProject() {
projectService.addProject(projectBean.getProjectDTO());
return ("");
}
}
...and her you can see my model, which gets its values out of a facelet...
#ManagedBean(name="ProjectData")
#SessionScoped
public class ProjectData {
private ProjectDTO projectDTO;
public ProjectData(){
projectDTO = new ProjectDTO();
}
public ProjectDTO getProjectDTO() {
return projectDTO;
}
public void setProjectDTO(ProjectDTO projectDTO) {
this.projectDTO = projectDTO;
}
public String getTitle() {
return projectDTO.getTitle();
}
public void setTitle(String title) {
projectDTO.setTitle(title);
}
}
My problem is now that it doesn't work. I think I need to inject the dependency between those two classes. But how? Is there a JSF-pro that can help me.
I would like to use annotations.
Thanks
Update after BalusC's post
I changed my code a little bit, but it still doesn't work. Any further advice, please.
#ManagedBean(name="projectData")
#SessionScoped
public class ProjectData {
...
#ManagedProperty(value="#{projectData}")
private ProjectData projectData;
The error com.sun.faces.mgbean.ManagedBeanCreationException says that the controller bean can not be created because projectData (the model-bean) is not found..
This should work:
#ManagedProperty(value="#{ProjectData}")
private ProjectData projectBean
That said, the normal practice is to start instance names with a lowercase. You also don't do in real
ProjectData ProjectData = new ProjectData();
but rather
ProjectData projectData = new ProjectData();
If you omit the (name="ProjectData") from the #ManagedBean, then it will automatically default to projectData.
As per your update:
The error com.sun.faces.mgbean.ManagedBeanCreationException says that the controller bean can not be created because projectData (the model-bean) is not found.
It's actually more telling that property projectData cannot be found. The property is not writable. In other words, the setter is missing. In the future please don't rephrase error messages and just copypaste them.
Okay guys I have found the answer:
there are missing get and set methods in my controller:
/*
* Getter and Setter
*/
public ProjectData getProjectData() {
return projectData;
}
public void setProjectData(ProjectData projectData) {
this.projectData = projectData;
}
Reference

Strange nullPointerException in Java

I'm writing an app for Java ME, and I need a class for holding some data(PhoneBook). When I'm trying to launch this app, I'm always getting a nullPointerException. I'm calling the constructor of a class, and it allocates memory for 10 elements, so it shouldn't be null. What am I doing wrong?
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class TinyMIDlet extends MIDlet implements CommandListener {
private PhoneBook phoneBook = new PhoneBook();
public void initPhoneBook() {
phoneBook.records[0].Name = new String("abc");
}
protected void startApp() {
initPhoneBook();
}
public class Record {
public String Name;
public String Number;
public String email;
public String Group;
}
public class PhoneBook {
public Record[] records;
PhoneBook() {
records = new Record[10];
}
}
}
The array of records isn't null, but each individual element of it is. You need to instantiate each element as well, right now it's just an array with 10 null entries.
phoneBook.records[0].Name = new String("abc");
should be
phoneBook.records[0] = new Record();
phoneBook.records[0].Name= new String("abc");// or = "abc"
I'm not reputable enough yet (heh) to edit Tom's detailed answer, but, to be precise
phoneBook.records[0] = new something();
should be
phoneBook.records[0] = new Record();

Resources