Unmarshal XML to different objects depending on Attribute using JAXB [duplicate] - java

This question already has answers here:
JAXB: how to unmarshal a List of objects of different types but with common parent?
(3 answers)
Closed 7 years ago.
I am trying to unmarshal the following XML:
<calcElement partname="driver">
<driverXs>300.00</driverXs>
<seq>1</seq>
</calcElement>
<calcElement partname="ratingData">
<baseMiles>6000</baseMiles>
<vehicleGroup>15</vehicleGroup>
<documentVersion>4</documentVersion>
</calcElement>
I have the following classes, which represent the 2 above instances of calcElement:
public abstract class CalcElement {
private String partName;
#XmlAttribute
public String getPartName() {
return partName;
}
public void setPartName(String partName) {
this.partName = partName;
}
}
public class DriverCalcElement extends CalcElement {
private String driverXs;
private String seq;
public String getDriverXs() {
return driverXs;
}
public void setDriverXs(String driverXs) {
this.driverXs = driverXs;
}
public String getSeq() {
return seq;
}
public void setSeq(String seq) {
this.seq = seq;
}
}
public class RatingDataCalcElement extends CalcElement {
private String baseMiles;
private String vehicleGroup;
private String documentVersion;
public String getBaseMiles() {
return baseMiles;
}
public void setBaseMiles(String baseMiles) {
this.baseMiles = baseMiles;
}
public String getVehicleGroup() {
return vehicleGroup;
}
public void setVehicleGroup(String vehicleGroup) {
this.vehicleGroup = vehicleGroup;
}
public String getDocumentVersion() {
return documentVersion;
}
public void setDocumentVersion(String documentVersion) {
this.documentVersion = documentVersion;
}
}
However I am unable to work out the combination of Annotations to add to the classes to successfully unmarshal (and marshal) this code.
What do I need to add to the classes to get this to work?

What you're trying to do isn't supported natively by JAXB. XML Schema 1.1 introduced the concept of a type alternative which you could use for determining the type of your element with an XPath expression, using the value of attributes on that element, but this isn't supported by JAXB 2.x (which is based on XML Schema 1.0).
You can do something similar with JAXB using xsi:type, but you would either need to change your document on disk or do a transform (e.g. using XSLT) to include the xsi:type attribute before passing it to the JAXB Unmarshaller. The values of xsi:type would be the type names you assign with your annotations. See the #XmlType annotation for how the type names of your classes are computed.

Related

Enums in Java VS Enums in C# [duplicate]

This question already has answers here:
C# vs Java Enum (for those new to C#)
(13 answers)
Is it possible to add custom properties to c# enum object?
(2 answers)
Closed 2 years ago.
I have a very basic question. In Java, it is possible to point attributes and variables to Enums, such as:
public enum DayTime{
Morning("Morning"),
Afternoon("Afternoon"),
Night("Night");
private string description;
Daytime(string description){
this.description = description;
}
public string getDescription(){
return description;
}
}
Is it possible to apply the same concept to C#? I am trying to get modular descriptions to products, whereas their name, contents and characteristics would be shown in a string of text, and Enums looked like the best alternative to modify this text according to which characteristic is selected.
C# enums are very basic compared to Java enums. If you want to simulate the same kind of behavior you need to use a class with an inner enum:
using System.Collections.Generic;
public sealed class DayTime
{
public static readonly DayTime Morning = new DayTime("Morning", InnerEnum.Morning);
public static readonly DayTime Afternoon = new DayTime("Afternoon", InnerEnum.Afternoon);
public static readonly DayTime Night = new DayTime("Night", InnerEnum.Night);
private static readonly List<DayTime> valueList = new List<DayTime>();
static DayTime()
{
valueList.Add(Morning);
valueList.Add(Afternoon);
valueList.Add(Night);
}
//the inner enum needs to be public for use in 'switch' blocks:
public enum InnerEnum
{
Morning,
Afternoon,
Night
}
public readonly InnerEnum innerEnumValue;
private readonly string nameValue;
private readonly int ordinalValue;
private static int nextOrdinal = 0;
private string description;
internal DayTime(string name, InnerEnum innerEnum)
{
this.description = name;
nameValue = name;
ordinalValue = nextOrdinal++;
innerEnumValue = innerEnum;
}
public string Description
{
get
{
return description;
}
}
//the following methods reproduce Java built-in enum functionality:
public static DayTime[] values()
{
return valueList.ToArray();
}
public int ordinal()
{
return ordinalValue;
}
public override string ToString()
{
return nameValue;
}
public static DayTime valueOf(string name)
{
foreach (DayTime enumInstance in DayTime.valueList)
{
if (enumInstance.nameValue == name)
{
return enumInstance;
}
}
throw new System.ArgumentException(name);
}
}
Given this complexity, it may be best to rewrite your logic in a way that's more natural for C# without using enums.

POJO to JSON conversion not working for String variable starting with "is"

String variable - "isInitial" in below example is not getting converted into JSON. Is it possible to generate JSON structure for isInitial variable without modifying the EmployeePOJO class?
PS: converting the getter method to getIsInitial works.
Please find below POJO class used for generating the JSON:
public class EmployeePOJO {
private String firstName;
private String lastName;
private String isInitial;
private boolean isFirstNameAvailable;
private boolean hasLastNameAvailable;
private String hasHouse;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String isInitial()
{
return this.isInitial;
}
public void setInitial(String pInitial)
{
this.isInitial = pInitial;
}
public String getHasHouse() {
return hasHouse;
}
public void setHasHouse(String hasHouse) {
this.hasHouse = hasHouse;
}
public boolean isFirstNameAvailable() {
return isFirstNameAvailable;
}
public void setFirstNameAvailable(boolean firstNameAvailable) {
isFirstNameAvailable = firstNameAvailable;
}
public boolean isHasLastNameAvailable() {
return hasLastNameAvailable;
}
public void setHasLastNameAvailable(boolean hasLastNameAvailable) {
this.hasLastNameAvailable = hasLastNameAvailable;
}
}
Please find below main logic for POJO conversion:
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
public class JacksonPojoToJson {
public static void main(String[] args) throws IOException {
// Create ObjectMapper
ObjectMapper mapper = new ObjectMapper();
EmployeePOJO employeePOJO = new EmployeePOJO();
employeePOJO.setFirstName("FIRST NAME");
employeePOJO.setFirstNameAvailable(true);
employeePOJO.setLastName("last name");
employeePOJO.setHasLastNameAvailable(true);
employeePOJO.setInitial("true");
// Convert object to JSON string
String json = mapper.writeValueAsString(employeePOJO);
System.out.println(json);
}
}
Bad naming conventions. If you are using IDE let the IDE generate the getters and setters for you.
The isInitial method can be used as getter for a Boolean variable. Not a String variable.
So you can fix your POJO class (https://en.wikipedia.org/wiki/Plain_old_Java_object)
or you can use the #JsonProperty annotation (https://fasterxml.github.io/jackson-annotations/javadoc/2.8/com/fasterxml/jackson/annotation/JsonProperty.html)
Use Lombok maven dependency for generate automatic getter & setter.
You have to use the correct naming of getters and setters for your variable for example:
private String isInitial;
For the above variable getter setter should be:
public String getIsInitial()
{
return this.isInitial;
}
public void setIsInitial(String isInitial)
{
this.isInitial = isInitial;
}
Note: I don't know your use case but name like isXXXX used for getters of boolean variables.
I would recommend using Lombok's #Getter and #Setter annotations to auto-generate your getter and setter methods. Using these, you will not run into issues with naming conventions etc.
Please see the following URL for more information:
https://projectlombok.org/features/GetterSetter
#Loizos - Thanks a lot for the suggestion #JsonProperty, it worked fine. I was looking at a solution without modifying the class - EmployeePOJO (since it is legacy code which we dont want to touch).
I got this resolved by using Mixins, which does not require modification in EmployeePOJO file.
Sample code which worked for me:
public interface EmployeePOJOMixIn {
#JsonProperty("isInitial")
public abstract String isInitial();
}
Then adding this Mixin to mapper (this will vary based on whether you are using fasterxml or codehaus)
https://www.leveluplunch.com/java/tutorials/024-modifying-fields-external-domain-jackson-mixin/ and https://medium.com/#shankar.ganesh.1234/jackson-mixin-a-simple-guide-to-a-powerful-feature-d984341dc9e2 are good sites which I referred for the solution.
The reason for this is that the setters/getters for boolean variables do not follow the pattern setVariableName/getVariableName.
You could see in your own code that it is like this:
public String isInitial()
{
return this.isInitial;
}
public void setInitial(String isInitial)
{
this.isInitial = isInitial;
}
Quick fix would be to create the setters/getters for boolean variables manually.
This (setter/getter creation issue) usually happens in eclipse, but I think IntelliJ handles this right.

Finding non-referenced class attributes in Eclipse

I wonder if there are another ways to find attributes in specific class are non-referenced by other classes (I mean, non used attributes).
My way is like that, for example I have a class like:
public class EABHeaderInformation implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4986763088497593972L;
//BargainFinder - AlternateBooking
private int multiTicketSequencdNmbr;
private String resBookDesigCode;
private LocalDateTime departureDate;
private LocalDateTime lastTicketingDate;
private List<String> text;
private String validatingCarrierCode;
public String getValidatingCarrierCode() {
return validatingCarrierCode;
}
public void setValidatingCarrierCode(String validatingCarrierCode) {
this.validatingCarrierCode = validatingCarrierCode;
}
public int getMultiTicketSequencdNmbr() {
return multiTicketSequencdNmbr;
}
public void setMultiTicketSequencdNmbr(int multiTicketSequencdNmbr) {
this.multiTicketSequencdNmbr = multiTicketSequencdNmbr;
}
public String getResBookDesigCode() {
return resBookDesigCode;
}
public void setResBookDesigCode(String resBookDesigCode) {
this.resBookDesigCode = resBookDesigCode;
}
public LocalDateTime getDepartureDate() {
return departureDate;
}
public void setDepartureDate(LocalDateTime departureDate) {
this.departureDate = departureDate;
}
public LocalDateTime getLastTicketingDate() {
return lastTicketingDate;
}
public void setLastTicketingDate(LocalDateTime lastTicketingDate) {
this.lastTicketingDate = lastTicketingDate;
}
public List<String> getText() {
return text;
}
public void setText(List<String> text) {
this.text = text;
}}
It's a simple POJO with getter and setters. I check every getter and setter with 'Open Call Hierarchy' in Eclipse, to find out if the attribute is used by others or not. But it takes a lot of time when I work on bigger classes than this.
So, is there a faster way to do this? Thanks for replies.
Eclipse can already create a warning or error for unused private members, but for public ones the Eclipse stance has always been that it's not a valuable feature. I tend to disagree, because many users have a limited scope that would be useful (specifically, all, or a subset of, the projects in the workspace). See this feature request, this one, and this one.
There are some third party options, such as UCDetector and this simple plug-in example.
See also this SO question and the answers.

Map selected fields from multiple POJOs to create one POJO

I have a couple of objects from which selected members should be combined to create an output object. All these are POJOs. I am seeing that all object mappers work on a single POJO to another POJO level. Is there any mapper that supports what I am looking for? Of course, I understand that there is some mapping stuff that I need to specify.
Edit:
I know how to get this done by writings own Java class. I am just looking for a way to do it with one of the mapping libraries.
You aren't limited in what you require to be passed to your mapper. You can define it to accept several items and build the object based on the multiple inputs. Here is an example:
public class ClassOne {
private final String someProperty;
public ClassOne(String someProperty) {
this.someProperty = someProperty;
}
public String getSomeProperty() {
return someProperty;
}
}
public class ClassTwo {
private final String someOtherProperty;
public ClassTwo(String someOtherProperty) {
this.someOtherProperty = someOtherProperty;
}
public String getSomeOtherProperty() {
return someOtherProperty;
}
}
public class CombinedClass {
public static CombinedClass mapper(ClassOne one, ClassTwo two){
return new CombinedClass(one.getSomeProperty(), two.getSomeOtherProperty());
}
private final String someProperty;
private final String someOtherProperty;
private CombinedClass(String someProperty, String someOtherProperty) {
this.someProperty = someProperty;
this.someOtherProperty = someOtherProperty;
}
public String getSomeProperty() {
return someProperty;
}
public String getSomeOtherProperty() {
return someOtherProperty;
}
}

Structured data in java [duplicate]

This question already has answers here:
Struct like objects in Java
(20 answers)
Closed 9 years ago.
In C I would create a data structure as below:
struct file_data_format
{
char name[8][20];
float amp[8];
int filter[8];
};
extern struct file_data_format f_data;
Then I could read or write this whole structure to a file or memory location.
How would I do this in a class in java?
You should read basics of Java before asking. Structure in C can be written as Class in Java.
public class FileDataFormat implements Serializable {
String[][] name = new String[8][20];
float[] amp = new float[8];
int[] filter = new int[8];
public FileDataFormat() {
}
public void setName(String[][] name) {
this.name = name;
}
public String[][] getName() {
return this.name;
}
// next getters and setters
}
I pretty recommend OOP(encapsulation, polymorphism, inheritance).
If you want to achieve a similar effect, you can do the following.
Unfortunately, you don't have so much control over how it's represented in memory as you do in c
public class file_data_format
{
public char name[8][20];
public float amp[8];
public int filter[8];
}
...
public static void main()
{
file_data_format fdf = new file_data_format();
fdf.name = charArrayIGotFromSomewhere
}
public class FileDataFormat {
private String name;
private float amp;
private int filter;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getAmp() {
return amp;
}
public void setAmp(float amp) {
this.amp = amp;
}
public int getFilter() {
return filter;
}
public void setFilter(int filter) {
this.filter = filter;
}
}
The equivalent of a struct in Java is a JavaBean, as other answers has shown you.
From Wikipedia, a JavaBean :
is serializable
has a 0-argument constructor
allows access to properties using getter and setter methods.
To write and read it from file or memory, it is not as simple as in C. You would typically use Java Object serialization to write/read your objects to an ObjectInputStream/ObjectOutputStream, that could be attached to a file or a byte array.

Categories

Resources