Dozer: Map a field to function output - java

I am using Dozer to do object Mapping. Everything works reaaly well just that I'm not able to map this particular thing.
<mapping>
<class-a>User</class-a>
<class-b>UAUserBean</class-b>
<field>
<a>RightLst.Right</a>
<b>Rights</b>
<a-hint>Right</a-hint>
<b-hint>UARightBean</b-hint>
</field>
<field>
<a>RightLst.NumInLst</a>
<b>Rights.length</b>
</field>
</mapping>
//here RightLst is an object of a class and numInLst (int prop)
//rights is an array of objects
what i want to do is
lUser.getRightLst().setNumInLst(uaUserBean.getRights().length);
Any suggestions??
Thanks in advance.
User{
protected RightLst rightLst;
}
RightLst{
protected Integer numInLst;
protected Collection right = new ArrayList();
}
public class UAUserBean{
private UARightBean[] rights;
}

When you do this:
...
<b>rights.length</b>
</field>
Dozer will try to access the first position of the rights array and call the getter for the length property on an instance of UARightBean (which is the type of the array), obviously the length property doesn't exist in UARightBean and Dozer will throw an Exception.
I suggest to create a getter method in UAUserBean to return the length of the rights property, it would look like this:
class UAUserBean {
...
public int getRightsLength() {
return rights != null ? rights.length : 0;
}
}
Mapping file:
<class-a>User</class-a>
<class-b>UAUserBean</class-b>
<field>
<a>rightLst.numInLst</a>
<b>rightsLength</b>
</field>
If you can't modify UAUserBean, your last option would be a custom converter from UARightBean[] to Integer, but it would look ugly.

Related

How can I use dozer for Set<Object> mapping Set<String>, while Set<String> contains obj.getProperty()

How can I use dozer for field Set<Object> mapping Set<String>, while Set<String> contains obj.getProperty().
I want to map User.roleSet to UserVO.roleNames, which contains Role.name.
public class User {
private Integer id;
private Set<Role> roleSet;
}
public class UserVO {
private Integer id;
private Set<String> roleNames;
}
public class Role {
private Integer id;
private String name;
}
There is a couple of ways to deal with the problem but the first thing that you have to know about that is mapping between collections is little problematic due to Java generics. They are not available on the runtime and you have to be aware of it.
So in this case on the runtime you will have to collections and based on the collection type you won't be able to determine the collection source type (only by checking some element it will be available).
In this case I think the best approach would be define you own custom converter (which you have to register on the dozer config file within custom-converters tags). That part will look like something like that:
<configuration>
<custom-converters>
<converter type="ToRoleNameConverter">
<class-a>Role</class-a>
<class-b>java.lang.String</class-b>
</converter>
</custom-converters>
The source code of that converter:
public class ToRoleNameConverter extends DozerConverter<Role, String> {
#SuppressWarnings("unchecked")
public ToRoleNameConverter() {
super(Role.class, String.class);
}
#Override
public String convertTo(Role source, String destination) {
return source.getName();
}
#Override
public Role convertFrom(String source, Role destination) {
throw new UnsupportedOperationException("Unsupported operation exception!");
}
}
With that converter you could use define how your basic class and embedded collection should be mapped. Additional dozer configuration will be needed:
<mapping>
<class-a>User</class-a>
<class-b>UserDto</class-b>
<field>
<a>roles</a>
<b>roleNames</b>
<a-hint>Role</a-hint>
<b-hint>java.lang.String</b-hint>
</field>
</mapping>
With the given configuration you should try to map:
User user = new User()
user.setUserId(1)
user.setRoles(Sets.newHashSet(new Role(1, "admin"), new Role(2, "manager")))
UserDto map = mapper.map(user, UserDto.class)
And get the results:
User{id=1, roles=[Role{id=2, name=manager}, Role{id=1, name=admin}]}
UserDto{id=1, roleNames=[manager, admin]}
Hope that explain your question!

Return a list (inside an object) from myBatis (Java)

I need some help here, I am trying to return a list of objects, inside a parent object using myBatis.
THE PROBLEM :
Before you begin reading the code below - My error that I get back is :
SqlSession operation; nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4102
What is interesting here is that this somehow means I am hitting the stored procedure, seeing the amount of data there is, and erroring due to having too many results because myBatis thinks I am using selectOne() - Which is not true? I will add, that 4102 is the exact number of records in the table I am trying to pull this data from.
MY CODE :
Here are the result maps for the parent and child objects :
<resultMap id="ParentObjectMap" type="com.company.product.mybatis.model.ParentObject">
<collection property="children" resultMap="childrenMap"/>
</resultMap>
<resultMap id="childrenMap" type="com.company.product.mybatis.model.ChildObject">
<id column="ChildId" jdbcType="BIGINT" property="childId" />
<result column="Name" jdbcType="VARCHAR" property="name" />
</resultMap>
Here is the code for each of the above maps.
public class ParentObject implements Serializable {
private long id;
private List<ChildObject> childrenMap;
/* GETTERS AND SETTERS EXCLUDED FOR BREVITY. */
}
And the class for the Child object :
public class ChildObject implements Serializable {
private long childId;
private String name;
/* GETTERS AND SETTERS REMOVED FOR BREVITY. */
}
Here Is the Stored Procedure which I am calling, which aims to return the data :
ALTER PROCEDURE dbo.PR_Children_Get
AS
SET NOCOUNT ON
BEGIN
SELECT
tp.ChildId,
tp.Name
FROM dbo.Children tp WITH (NOLOCK)
END
GO
And here is how I am executing that procedure in my mapper :
<select id="getChildren" resultMap="ParentObjectMap">
exec [dbo].[PR_Children_Get]
</select>
Here is the interface through which I access my mapper :
#Override
public ParentObject getChildren() throws Exception {
ParentObject result = ParentObjectMapper.getChildren();
return result;
}
Here is the interface of that ParentObjectMapper :
/* Hiding imports for brevity */
public interface ParentObjectMapper {
// Get the list children, the list should be a property within the parent object.
ParentObject getChildren();
}
I suppose you execute through a mapper interface and the method would be: ParentObject getChildren(); this explicitly expect a single result because this is not a collection type, then the error you got.
But I'm not telling you should change to List<ParentObject> getChildren(); to avoid this error ... or maybe you should ... for a while, because it would help understanding the issue:
With your code Mybatis creates a new ParentObject for each result row because the parentId is never returned and Mybatis does not assume you have a single parent. Then the query shall return a parentId column and the ParentObjectMap start with <id column="parentId" property="id"/>, so that Mybatis knows how to group children by their parent.

Converting j8583 object having one getter with params in Dozer

I have an IsoMessage object (https://github.com/chochos/j8583/blob/master/src/main/java/com/solab/iso8583/IsoMessage.java) that has an internal array which I can only access through a getField(int) method.
public class IsoMessage {
#SuppressWarnings("rawtypes")
private IsoValue[] fields = new IsoValue[129];
.........
.........
.........
/** Returns the IsoValue for the specified field. First real field is 2. */
#SuppressWarnings("unchecked")
public <T> IsoValue<T> getField(int field) {
return fields[field];
}
I need to read all the attributes stored on the fields array, by calling getField(param Number), and move them to a new object that has a Map, and want to achieve this using dozer.
the object that I need to translate to:
public class TransactionInstance implements Serializable {
private static final long serialVersionUID = 3429335891821913088L;
private String transactionName;
private Map<String, String> parameters;
I was experimenting with this dozer configuration hoping to get the field 1 from my isoMessage object
<mapping map-id="a">
<class-a>com.solab.iso8583.IsoMessage</class-a>
<class-b>j8583.example.TransactionInstance</class-b>
<field>
<a get-method="getField" key="1">field</a>
<b map-set-method="put">parameters</b>
</field>
</mapping>
But I'm stuck at getting the value from the original object with this exception:
Exception in thread "main" org.dozer.MappingException: No read or write method found for field (field) in class (class com.solab.iso8583.IsoMessage)
at org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.determinePropertyType(GetterSetterPropertyDescriptor.java:319)
at org.dozer.propertydescriptor.GetterSetterPropertyDescriptor.getPropertyType(GetterSetterPropertyDescriptor.java:76)
at org.dozer.fieldmap.MapFieldMap.determineActualPropertyType(MapFieldMap.java:170)
at org.dozer.fieldmap.MapFieldMap.getSrcFieldValue(MapFieldMap.java:95)
I was checking this post https://github.com/DozerMapper/dozer/issues/111 and How to pass `this` to Dozer field mapping? bus still stuck in the same place, also I was wondering if I can achieve this by using the API so I can tell dynamically which fields I want to get from the original bean
I'm not familiar with Dozer, but field 1 is the bitmap. getField(1) returns null.
I finally foud the rigth mapping using the capability that dozer has to access the internal objects directly (http://dozer.sourceforge.net/documentation/custommethods.html).
<mapping>
<class-a is-accessible="true">com.solab.iso8583.IsoMessage</class-a>
<class-b>j8583.example.TransactionInstance</class-b>
<field>
<a>fields[3]</a>
<b set-method="addParameter" map-set-method="addParameter" key="field3">parameters
</b>
</field>
</mapping>

Dozer: map single field to Set

How do you map a single field into a Set in Dozer?
I have a class like:
class FooDTO {
private IdDto bar;
private IdDto baz;
}
class FooDomainObject {
private List<Id> ids;
}
I'd like to map bar and baz into the ids list, but I can't get it to do this.
I found this on the Dozer support list:
http://sourceforge.net/projects/dozer/forums/forum/452530/topic/1557144
Basically, you use this syntax:
<field>
<a>bar</a>
<b>ids[0]</b>
<b-hint>org.foo.Id</b-hint>
</field>
<field>
<a>baz</a>
<b>ids[1]</b>
<b-hint>org.foo.Id</b-hint>
</field>
Is there a way to do sth. like this :
<mapping>
<class-a>SourceObject</class-a>
<class-b>blaObject</class-b>
<field>
<a>sourceObjectSubObject[standardID].fielda</a>
<b>blaDestField</b>
</field>
</mapping>
Where the standardID is a field in the sourceObject,
and the sourceObjectSubObject is a List<sourceObjectSubObject>.

Java/JAXB: Unmarshall XML elements with same name but different attribute values to different class members

I am trying to parse XML that has several "Fields" elements to different class members according to one of their attributes.
Here is the XML:
<Series>
<Fields type="SelectedFields" operation="SUM">
<Field name="Remaining" />
<Field name="Invested" />
</Field>
<Fields type="FirstSelectedFields" operation="SUM">
<Field name="Estimated" />
</Field>
</Series>
And here is the java class it should be mapped to:
public class APMSeries {
private List<Field> selectedFields;
private List<Field> firstSelectedFields;
}
Can anyone tell me how can I set the Fields element with attribute type="SelectedFields" to the selectedFields member and the Fields element with the attribute type="FirstSelectedFields" to the firstSelectedFields member?
public class APMSeries {
#XmlElementWrapper(name="SelectedFields")
private List<Field> selectedFields;
#XmlElementWrapper(name="FirstSelectedFields")
private List<Field> firstSelectedFields;
}

Categories

Resources