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>
Related
I have kind of a combination-follow up question to [1] and [2].
I have a POJO with a field I want to persist in - and read from - Elasticsearch:
#Document
public class MyPojo {
private String level3;
// getters/setters...
}
For convenience and because the property is also being persisted (flatly) into postgres, the property level3 should be a String, however it should be written into ES as a nested object (because the ES index is defined elsewhere).
The current solution is unsatisfactory:
#Document
#Entity
public class MyPojo {
#Column(name = "level3)
#Field(name = "level3", type = FieldType.Keyword)
#ValueConverter(MyConverter.class)
private String level3;
// getters/setters...
}
with the object path "level1.level2.level3" hardcoded within MyConverter, which converts from Map<String, Object> to String (read) and from String to Map<String, Object> (write). Because we potentially need to do this on multiple fields, this is not a really viable solution.
I'd rather do something like this:
#Document
#Entity
public class MyPojo {
#Column(name = "level3)
#Field(name = "level1.level2.level3", type = FieldType.Keyword)
#ValueConverter(MyConverter2.class)
private String level3;
// getters/setters...
}
which does not work (writing works fine, while reading we get the "null is not a map" error from [2]).
Is this at all possible (if I understood [2] correctly, no)? If not, is there another way to achieve what I want without hardcoding and an extra converter per field?
Can I somehow access the #Field annotation within MyConverter (e.g. the name), or can I somehow supply additional arguments to MyConverter?
[1] Spring data elasticsearch embedded field mapping
[2] Spring Elasticsearch: Adding fields to working POJO class causes IllegalArgumentException: null is not a Map
There are several REST calls that require the same JSON entity with a different set of attributes. Example of the entity:
public class JsonEntity
{
public String id;
public String name;
public String type;
public String model;
}
JsonEntity is a part of the complex responses of different calls. The first call requires the whole JsonEntity without changes. Second call requires JsonEntity without type and model attributes. Thrid one requires JsonEntity without name attribute.
Is there any way to retrieve the same JSON entity with a particular set of attributes depending on the particular context (except separating JsonEntity) using Jackson?
I see 3 ways of doing this:
1. Use #JsonGetter
This annotation tells jackson to use a metho rather than a field for serialization.
Create 3 subclasses of JsonEntity, one for each response. Change JsonEntity and use #IgnoreField on every field, make them protected if possible. On each subclasses, create specific getter for the fields you need, example:
public class JsonEntitySecondCall extends JsonEntity
{
#JsonGetter("id")
public String getId(){
return id;
}
#JsonGetter("name")
public String getName(){
return name;
}
}
Also, create a clone/copy constructor for JsonEntity. For your second call, create a new JsonEntitySecondCall by cloning the original JsonEntity, and use it in your API. Because of the anotation, the created Object will only serialisze the given fields. I don't this you can just cast your object, because Jackson uses reflection.
2. Use #AnyGetter
the AnyGetter annotaiton allows you to define a map of what will be serialized:
private Map<String, Object> properties = new HashMap<>();
#JsonAnyGetter
public Map<String, Object> properties() {
return properties;
}
Now you just need to tell your JsonEntity what properties it needs to return before each call (you could create 3 methods, one for each context, and use an enum to set which one must be used.).
3. Use #JsonInclude(Include.NON_NULL)
This annotation tells Jackson not to serialize a field if it is null. You can then clone your object and set null the fields you don't want to send. (this only works if you shouldn't send null elements to the API)
For more on Jackson annotations use this link.
Well, I'm trying to parse objects and I'm having so much issues.
My classes are like this:
-Entidad-
public class Entidad{
private Long codEntidad;
private Set<Comunicacion> comunicacion;
/*------------ Getter and Setters --------------*/
}
-Comunicacion-
public class Comunicacion {
private Entidad entidad;
private Long codComunicacion;
/*------------ Getter and Setters --------------*/
}
I need to parse to DTO objects:
-EntidadDTO-
public class EntidadDTO{
private Long codEntidad;
private Set<ComunicacionDTO> comunicacionDto;
/*------------ Getter and Setters --------------*/
}
-ComunicacionDTO-
public class ComunicacionDTO {
private EntidadDto entidadDto;
private Long codComunicacion;
/*------------ Getter and Setters --------------*/
}
I tried to use:
BeanUtils.copyProperties(entidad, entidadDto);
It seems that the parse is success but the property entidadDto.getComunicacionDto(); is a hashMap of Comunicacion (not ComunicacionDTO)
Should I try to make a custom parse with reflection?
Also I'd like to use this to parse more objects with a similar structure.
Thanks!
Try dozer. You can define mappings from bean to bean using it.
http://dozer.sourceforge.net/
Why you want to parse java object and move data to other java object?
Parsing is for unstructured strings not for objects.
Use setters/getters to move data from one object to the other, using reflection will make you cry when you start doing refactorings.
I am using JAXB-impl. I need to be able to map nested elements to class fields as simple types. For example:
<mapping>
<search>
<channel>main-channel</channel>
<url>my-channel-url</url>
</search>
<items>
<item>first</item>
<item>second</item>
<item>third</item>
</items>
</mapping>
Assuming I need to bind "url" tag to a field in the class, this will not work (of course):
class Mapping{
#XmlElement
private String url;
}
#XmlElementWrapper, is for collections only. I have seen some post about using eclipse MOXy, and utilize #XmlPath, but this is not an option. It has to be JAXB-impl.
for reference:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/XPath#Marshal_to_XML_-_MOXy_Customization_.231_-_Grouping_Element
Is there a way to get this mapping without having to create these extra nested classes ?
With additional class Search, but this class is private nested class, and not used outside of Mapping class.
public API of class Mapping returns url as expected
#XmlAccessorType(XmlAccessType.FIELD)
class Mapping
{
#XmlAccessorType(XmlAccessType.FIELD)
private static class Search
{
private String channel;
private String url;
}
private Search search;
public String getUrl()
{
return search == null ? null : search.url;
}
}
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.