Jackson fails to convert Java pojo to XML - serialization

I am trying to serialize a class Pojo to XML with Jackson XML mapper.
Here is how the XML looks and i represented with objects, also:
XML
<Class>
<ClassStudent Type="20">
<Student Age="2" Id="2">5.18</Student>
<Student Age="1" Id="1">4.863</Student>
</ClassStudent>
<ClassStudent Type="226">
<Student Age="3" Id="6" SpecialExpression="Good">1.91</Student>
<Student Age="1" Id="7" SpecialExpression="Prospective">1.89</Student>
</ClassStudent>
</Class>
OBJECT
public class Class{
#JsonProperty("ClassStudent")
private List<ClassStudent> classStudents;
}
public class ClassStudent{
#JsonProperty("Type")
private String type;
#JsonProperty("Student")
private List<Student> student;
}
public class Student{
#JsonProperty("Age")
private String age;
#JsonProperty("Id")
private String id;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonProperty("SpecialExpression")
private String specialExpression;
private Double evaluation;
}
I get an unrecognized field on Student level, not recognized field "Age"....

Related

Duplicate fields in data classes that extend other (sealed) classes?

When a data class extends a sealed class containing a non-abstract open val property, the generated child data class contains private fields that duplicate the private fields of the parent class.
sealed class Foo(open val field1: String? = null)
data class Bar(override val field1: String? = null) : Foo(field1)
Output from javap -p Foo.class:
public abstract class com.example.Foo {
private final java.lang.String field1;
public java.lang.String getField1();
private com.example.Foo(java.lang.String);
com.example.Foo(java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker);
public com.example.Foo(java.lang.String, kotlin.jvm.internal.DefaultConstructorMarker);
}
And javap -p Bar.class:
public final class com.example.Bar extends com.example.Foo {
private final java.lang.String field1;
public java.lang.String getField1();
public com.example.Bar(java.lang.String);
public com.example.Bar(java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker);
public com.example.Bar();
public final java.lang.String component1();
public final com.example.Bar copy(java.lang.String);
public static com.example.Bar copy$default(com.example.Bar, java.lang.String, int, java.lang.Object);
public java.lang.String toString();
public int hashCode();
public boolean equals(java.lang.Object);
}
The bytecode for Bar.class contains its own private field field1; the field in the parent class does not appear to be re-used by the child class.
When using frameworks that set fields using reflection, which field will be set? Why is the field in the parent class not re-used by the child class? Is there a way to change the visibility of the field in the parent class to protected so it can be re-used by the child class?
In that caseBar holds the field indeed twice. Two alternatives to have a single field:
sealed class Foo(val field1: String?)
data class Bar(private val hiddenField1: String? = null) : Foo(hiddenField1)
or
sealed class Foo {
abstract val field1: String?
}
data class Bar(override val field1: String? = null) : Foo()
The field is not reused because you declared a separate property, which has its own backing field. If you want to reuse the field, change your code to:
sealed class Foo(val field1: String? = null)
data class Bar(field1: String? = null) : Foo(field1)
When using frameworks that set fields using reflection, which field will be set?
It depends on the class you use. Foo::class.java.getDeclaredField() or Bar::class.java.getDeclaredField().
See:
https://programming.guide/java/accessing-private-fields-of-superclass-through-reflection.html
What is the difference between getFields and getDeclaredFields in Java reflection
Why is the field in the parent class not re-used by the child class?
Why should it? You defined a field-backed property field1 in both classes. Both fields will exist but getField1() method is overridden by child class to return child class' field.
Is there a way to change the visibility of the field in the parent class to protected so it can be re-used by the child class?
Fields of lateinit properties have the same visibility as the getters. But I'm not sure that's what you want.
How about this?
sealed class Foo {
abstract val field1: String?
}
data class Bar(override val field1: String? = null) : Foo()
See discussion here: https://twitter.com/orangy/status/1033067930248867840

Java: org.codehaus.jackson: How deserialize from string to Enum?

I has POJO
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyPojo implements Serializable {
#JsonProperty("id")
private int id;
#JsonProperty("type")
private MyTypeEnum type;
}
I deserialize from string (json) using annotation: org.codehaus.jackson.annotate.JsonProperty.
And it's work fine.
But what about Enum? How I can deserialize from string to enum (e.g. property "type") in uppercase?
Here my enum:
import org.codehaus.jackson.annotate.JsonProperty;
public enum Type {
#JsonProperty("text")
TEXT("text"),
#JsonProperty("external")
EXTERNAL("external"),
#JsonProperty("event")
EVENT("event"),
#JsonProperty("post")
POST("post"),
UNKNOWN("Unknown");
private String name;
private Type(String name) {
this.name = name;
}
private static Type[] genderList = Type.values();
public String getName() {
return name;
}
}
`
Error:
getLastPromotion: errorMessage: Can not construct instance of com.myproject.Type from String value 'external': value not one of declared Enum instance names
org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.bnmt.main.classEnum.PromotionObjectType from String value 'external': value not one of declared Enum instance names
at org.codehaus.jackson.map.deser.StdDeserializationContext.weirdStringException(StdDeserializationContext.java:243)
at org.codehaus.jackson.map.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:80)
at org.codehaus.jackson.map.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:23)
at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:299)
at org.codehaus.jackson.map.deser.SettableBeanProperty$FieldProperty.deserializeAndSet(SettableBeanProperty.java:579)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:697)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580)
at org.codehaus.jackson.map.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:104)
at org.codehaus.jackson.map.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2732)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1863)

WCF,Soap -> How can I eliminate an Element-Name in [MessageBodyMember]

I am building a SOAP Server with WCF in C#.
I have an Request from a Client thats looks like that :
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<sendLocalListRequest xmlns="urn://Ocpp/Cp/2012/06/">
<updateType>Full</updateType>
<listVersion>5678</listVersion>
<localAuthorisationList>
<idTag>1111111</idTag>
<idTagInfo>
<status>Accepted</status>
<expiryDate>2015-10-27T00:00:00</expiryDate>
<parentIdTag>555</parentIdTag>
</idTagInfo>
</localAuthorisationList>
<localAuthorisationList>
<idTag>2112432</idTag>
<idTagInfo>
<status>Accepted</status>
<expiryDate>2015-10-29T00:00:00</expiryDate>
<parentIdTag>555</parentIdTag>
</idTagInfo>
</localAuthorisationList>
<localAuthorisationList>
<idTag>44444444</idTag>
<idTagInfo>
<status>Accepted</status>
<expiryDate>2015-10-29T00:00:00</expiryDate>
<parentIdTag>2222</parentIdTag>
</idTagInfo>
</localAuthorisationList>
<hash>bhghs77767676777</hash>
</sendLocalListRequest>
I have to get this Request and store the Data between the Elements localAuthorisationList in a file on harddisk.
I made an [MessageContract] that Looks :
[MessageContract(IsWrapped = true, WrapperName = "sendLocalListRequest",
WrapperNamespace = "urn://Ocpp/Cp/2012/06/")]
public class sendLocalListRequest
{
[MessageBodyMember(Order=1)]
public UpdateType updateType;
[MessageBodyMember(Order=2)]
public int listVersion;
[MessageBodyMember(Order=3)]
public localAuthorisation[] localAuthorisationList;
[MessageBodyMember(Order=4)]
public string hash;
}
[DataContract(Namespace = "urn://Ocpp/Cp/2012/06/")]
public class localAuthorisation
{
[DataMember(IsRequired=true, Name = "idTag", Order = 1)]
public string idTag;
[DataMember(Name="idTagInfo", Order=2)]
public Data idTagInfo;
}
[DataContract(Namespace = "urn://Ocpp/Cp/2012/06/")]
public class Data
{
[DataMember(Name = "status", Order=1)]
public string Status;
[DataMember(Name = "expiryDate", Order=2)]
public DateTime ExDate;
[DataMember(Name = "parentIdTag", Order = 3)]
public string parentTag;
}
But with the WCFTestClient I get the following Request :
<s:Body>
<sendLocalListRequest xmlns="urn://Ocpp/Cp/2012/06/">
<updateType>Differential</updateType>
<listVersion>0</listVersion>
<localAuthorisationList xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<localAuthorisation>
<idTag>sfdsdgfg</idTag>
<idTagInfo>
<ExDate>2015-11-02T16:37:00</ExDate>
</idTagInfo>
</localAuthorisation>
<localAuthorisation />
</localAuthorisationList>
<hash i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
</sendLocalListRequest>
</s:Body>
My problem is, that I have an element too much (localAuthorisationList or localAuthorisation). Can I eliminate one Element? And how?
Thank you for your help
Tom

How to define message contract to get this schema?

How can i define the Message contract to get this XML SOAP format?
Schema:
<List>
<Exclusions>
<ExclusionID>123</ExclusionID>
<ExclusionID>656</ExclusionID>
</Exclusions>
</List>
I created the class file as mention below but it gives the response different
<DataContract> _
Public Class List
''' <remarks/>
Private _exclusions As Exclusions
<DataMember()> _
Public Property Exclusions() As Exclusions
Get
Return _exclusions
End Get
Set(ByVal value As Exclusions)
_exclusions = value
End Set
End Property
End Class
<DataContract>
Public Class Exclusions
<DataMember>
Public ExclusionID As ExclusionID()
End Class
<MessageContract>
Public Class ExclusionID
<MessageBodyMember(Name:="")>
Public Value As String
End Class
My response is like this:
<List >
<Exclusions >
<ExclusionID>
<ExclusionID>
<Value>123</Value>
</ExclusionID>
<ExclusionID>
<Value>145</Value>
</ExclusionID>
</ExclusionID>
</Exclusions>
</List>
How to achive the proper message using Message contract?
VB.net is not installed in my VS. C# code below for your reference.
//class definition
public class List {
[MessageBodyMember]
public Exclusions Exclusions { get; set; }
}
[CollectionDataContract(Name="Exclusions", ItemName="Exclusion")]
public class Exclusions : List<String> {
}
//help method
static void WriteMessage(Message message, String filePath) {
using (var writer = new XmlTextWriter(filePath, Encoding.UTF8)) {
message.WriteMessage(writer);
}
}
//code
var myList = new List();
myList.Exclusions = new Exclusions();
myList.Exclusions.Add("123");
myList.Exclusions.Add("656");
using (var message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10,
"http://127.0.0.1:3333/someaction", myList)) {
WriteMessage(message, "a.xml");
}

Can I have a collection of IUserType instances?

Is it possible to have a collection of entities that are mapped via an IUserType? For example:
class Foo
{
public int Id { get; set; }
public ISet<Special> Items { get; set; }
}
class Special
{
public Special(string columnValue)
{
_val = columnValue;
}
public override string ToString()
{
return _val.TranformInInterestingWays();
}
private string _val;
}
class SpecialUserTypeForMapping : IUserType
{
// assume that all the right stuff is here
// for using the non-default constructor on the way in
// and calling ToString() on the way out
}
If I'm reading the documentation correctly, neither the <set>, <one-to-many>, <many-to-many>, nor <class> element supports the "type" attribute as is used to apply IUserType mapping to <property>s. So how would I go about mapping this?
The most expedient solution seems to be to use the <element> element, like so:
<class name="Foo" table="foos">
<id name="Id" />
<set name="Items" table="foo_special">
<key column="fooId" />
<element column="special_value" type="SpecialUserTypeForMapping" />
</set>
</class>
Retrieving different Foo instances from the DB is no problem, but it's not clear whether it's possible to write queries against the special_value column, which is a requirement in my scenario. This question seems to indicate that it's not.