JAXB, annotations for setter/getter - java

#XmlType
#XmlAccessorType(XmlAccessType.FIELD) // here I need this access
public class User implements Serializable
{
// ...
#XmlTransient
private Set<Values> values;
// ...
#XmlElement
private Set<History> getXmlHistory()
{
return new CustomSet<Values, History>(Values);
}
private void setXmlHistory(final Set<History> aHistory)
{
this.values = new HashSet<Values>();
}
}
When I am create User object in Java code and after create XML, then all normally.
But when I try to get User-object from XML, then field values always null. So setter not working here. May be setter needs some annotation too?
XML looks like
<user>
...
<xmlHistory>
// ... record 1
</xmlHistory>
<xmlHistory>
// ... record 2
</xmlHistory>
</user>

I do not believe that this is a JAXB problem, as the following model will work:
package forum10617267;
import java.io.Serializable;
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlType
#XmlAccessorType(XmlAccessType.FIELD) // here I need this access
public class User implements Serializable {
#XmlTransient
private Set<History> history = new HashSet<History>();
#XmlElement
private Set<History> getXmlHistory() {
return history;
}
private void setXmlHistory(final Set<History> aHistory) {
this.history = aHistory;
}
}
The problem you are seeing is a result of the logic you have in your get/set methods. Since your values field is not initialized, I am not sure how CustomSet would be able to update it.
package forum10617267;
import java.io.Serializable;
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlType
#XmlAccessorType(XmlAccessType.FIELD) // here I need this access
public class User implements Serializable {
#XmlTransient
private Set<Values> values;
#XmlElement
private Set<History> getXmlHistory() {
return new CustomSet<Values, History>(values);
}
private void setXmlHistory(final Set<History> aHistory) {
this.values = new HashSet<Values>();
}
}

Related

How can JAXB be used to map attributes on an element to fields of an intrinsic property of a POJO?

Let's pretend I have the following XML:
<company name="Sun" country="Atlantis" state="Syracuse" city="Troy">
</company>
With JAXB, and without using third-party extensions such as EclipseLink's #XmlPath, is there a way to unmarshall it into the following POJO structure:
#XmlRootElement
public class Company {
private String name;
private Address address;
// getters and setters
}
public class Address {
private String country;
private String state;
private String city;
// getters and setters
}
company.getAddress().getCountry(); // Atlantis
This particular scenario can be handled using an XmlAdapter:
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.time.format.DateTimeFormatter;
public class CompanyAdapter extends XmlAdapter<CompantType, Company> {
#Override
public CompanyType marshal(Company in) throws Exception {
CompanyType out = new CompanyType();
out.setName(in.getName());
out.setCountry(in.getAddress().getCountry());
// ...
return out;
}
#Override
public Company unmarshall(CompanyType in) throws Exception {
Company out = new Company();
out.setName(in.getName());
Address add = new Address();
add.setCountry(in.getCountry());
out.setAddress(add);
// ...
return out;
}
}

How to exclude property from Lombok builder?

I have a class called as "XYZClientWrapper" , which have following structure:
#Builder
XYZClientWrapper{
String name;
String domain;
XYZClient client;
}
What I want no build function generated for property XYZClient client
Does Lombok supports such use case?
Yes, you can place #Builder on a constructor or static (factory) method, containing just the fields you want.
Disclosure: I am a Lombok developer.
Alternatively, I found out that marking a field as final, static or static final instructs #Builder to ignore this field.
#Builder
public class MyClass {
private String myField;
private final String excludeThisField = "bar";
}
Lombok 1.16.10
Create the builder in code and add a private setter for your property.
#Builder
XYZClientWrapper{
String name;
String domain;
XYZClient client;
public static class XYZClientWrapperBuilder {
private XYZClientWrapperBuilder client(XYZClient client) { return this; }
}
}
Here is my preferred solution. With that, you can create your field client at the end and have it depending on other fields that previously set by the builder.
XYZClientWrapper{
String name;
String domain;
XYZClient client;
#Builder
public XYZClientWrapper(String name, String domain) {
this.name = name;
this.domain = domain;
this.client = calculateClient();
}
}
For factory static method example
class Car {
private String name;
private String model;
private Engine engine; // we want to ignore setting this
#Builder
private static Car of(String name, String model){
Car car=new Car();
car.name = name;
car.model = model;
constructEngine(car); // some static private method to construct engine internally
return car;
}
private static void constructEngine(Car car) {
// car.engine = blabla...
// construct engine internally
}
}
then you can use as follows:
Car toyotaCorollaCar=Car.builder().name("Toyota").model("Corolla").build();
// You can see now that Car.builder().engine() is not available
Notice the static method of will be called whenever build() is called, so doing something like Car.builder().name("Toyota") won't actually set the value "Toyota" into name unless build() is called and then assigning logic within the constructor static method of is executed.
Also, Notice that the of method is privately accessed so that build method is the only method visible to the callers
I found that I was able to implement a "shell" of the static Builder class, add the method I want to hide with a private access modifier, and it is no longer accessible in the builder. Likewise I can add custom methods to the builder as well.
package com.something;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import java.time.ZonedDateTime;
#Data
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class MyClass{
//The builder will generate a method for this property for us.
private String anotherProperty;
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "localDateTime", column = #Column(name = "some_date_local_date_time")),
#AttributeOverride(name = "zoneId", column = #Column(name = "some__date_zone_id"))
})
#Getter(AccessLevel.PRIVATE)
#Setter(AccessLevel.PRIVATE)
private ZonedDateTimeEmbeddable someDateInternal;
public ZonedDateTime getSomeDate() {
return someDateInternal.toZonedDateTime();
}
public void setSomeDate(ZonedDateTime someDate) {
someDateInternal = new ZonedDateTimeEmbeddable(someDate);
}
public static class MyClassBuilder {
//Prevent direct access to the internal private field by pre-creating builder method with private access.
private MyClassBuilder shipmentDateInternal(ZonedDateTimeEmbeddable zonedDateTimeEmbeddable) {
return this;
}
//Add a builder method because we don't have a field for this Type
public MyClassBuilder someDate(ZonedDateTime someDate) {
someDateInternal = new ZonedDateTimeEmbeddable(someDate);
return this;
}
}
}
I found one more solution
You can wrap your field into initiated final wrapper or proxy.
The easiest way to wrap it into AtomicReference.
#Builder
public class Example {
private String field1;
private String field2;
private final AtomicReference<String> excluded = new AtomicReference<>(null);
}
You can interact with it inside by get and set methods but it won't be appeared in builder.
excluded.set("Some value");
excluded.get();
Adding a so called 'partial builder' to the class with Lombok #Builder can help. The trick is to add a inner partial builder class like this:
#Getter
#Builder
class Human {
private final String name;
private final String surname;
private final Gender gender;
private final String prefix; // Should be hidden, depends on gender
// Partial builder to manage dependent fields, and hidden fields
public static class HumanBuilder {
public HumanBuilder gender(final Gender gender) {
this.gender = gender;
if (Gender.MALE == gender) {
this.prefix = "Mr.";
} else if (Gender.FEMALE == gender) {
this.prefix = "Ms.";
} else {
this.prefix = "";
}
return this;
}
// This method hides the field from external set
private HumanBuilder prefix(final String prefix) {
return this;
}
}
}
PS: #Builder allows the generated builder class name to be changed. The example above assumed the default builder class name is used.
I have another approach using #Delegate and Inner Class, which supports "computed values" for the excluded fields.
First, we move the fields to be excluded into an Inner Class to avoid Lombok from including them in the Builder.
Then, we use #Delegate to expose Getters/Setters of the builder-excluded fields.
Example:
#Builder
#Getter #Setter #ToString
class Person {
private String name;
private int value;
/* ... More builder-included fields here */
#Getter #Setter #ToString
private class BuilderIgnored {
private String position; // Not included in the Builder, and remain `null` until p.setPosition(...)
private String nickname; // Lazy initialized as `name+value`, but we can use setter to set a new value
/* ... More ignored fields here! ... */
public String getNickname(){ // Computed value for `nickname`
if(nickname == null){
nickname = name+value;
}
return nickname;
}
/* ... More computed fields' getters here! ... */
}
#Delegate #Getter(AccessLevel.NONE) // Delegate Lombok Getters/Setters and custom Getters
private final BuilderIgnored ignored = new BuilderIgnored();
}
It will be transparent to outside of this Person class that position and nickname are actually inner class' fields.
Person p = Person.builder().name("Test").value(123).build();
System.out.println(p); // Person(name=Test, value=123, ignored=Person.BuilderIgnored(position=null, nickname=Test123))
p.setNickname("Hello World");
p.setPosition("Manager");
System.out.println(p); // Person(name=Test, value=123, ignored=Person.BuilderIgnored(position=Manager, nickname=Hello World))
Pros:
Do not force the excluded fields to be final
Support computed values for the excluded fields
Allow computed fields to refer to any fields set by the builder (In other words, allow the inner class to be non-static class)
Do not need to repeat the list of all fields (Eg. listing all fields except the excluded ones in a constructor)
Do not override Lombok library's #Builder (Eg. creating MyBuilder extends FooBuilder)
Cons:
The excluded fields are actually fields of Inner Class; however, using private identifier with proper Getters/Setters you can mimic as if they were real fields
Therefore, this approach limits you to access the excluded fields using Getters/Setters
The computed values are lazy initialized when Getters are invoked, not when .build().
One method I like and use is this.
Keep required parameters in constructor, and set optional through builder. Works if number of required is not very big.
class A {
private int required1;
private int required2;
private int optional1;
private int optional2;
public A(int required1, int required2) {
this.required1 = required1;
this.required2 = required2;
}
#Builder(toBuilder = true)
public A setOptionals(int optional1, int optional2) {
this.optional1 = optional1;
this.optional2 = optional2;
return this;
}
}
And then construct it with
A a = new A(1, 2).builder().optional1(3).optional2(4).build();
Nice thing with this approach is that optionals can also have default value.
One approach I have used before was to group instance fields into Configuration fields and Session fields. Configuration fields go as class instances and are visible to the Builder, while Session fields go into a nested private static class and are accessed via a concrete final instance field (which the Builder will ignore by default).
Something like this:
#Builder
class XYZClientWrapper{
private String name;
private String domain;
private static class Session {
XYZClient client;
}
private final Session session = new Session();
private void initSession() {
session.client = ...;
}
public void foo() {
System.out.println("name: " + name);
System.out.println("domain: " + domain;
System.out.println("client: " + session.client);
}
}
To exclude field from builder, try using #Builder.Default

JAXB unmarshall to multiple pojo's

I was trying to figure out if it is possible to unmarshall an xml element to multiple pojos. for example:
for xml:
<type>
<id>1</id>
<cost>12</cost>
<height>15</height>
<width>13</width>
<depth>77</depth>
</type>
Item class
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="type")
public class Item {
private Integer id;
private Double cost;
#XmlElement(name="id")
public Integer getId(){
return id;
}
#XmlElement(name="cost")
public Double getCost(){
return cost
}
}
ItemDimensions Class
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="type")
public class ItemDimensions {
private Integer height;
private Integer width;
private Integer depth;
#XmlElement(name="height")
public Integer getHeight(){
return height;
}
#XmlElement(name="width")
public Integer getWidth(){
return width;
}
#XmlElement(name="depth")
public Integer getDepth(){
return depth;
}
}
I have tried to accomplish something similar using a number of JAXB mappings generated by Netbeans 6.9 and a number of test classes but have gotten nowhwere. Does anyone know if this is something that can be done without any intermediary objects?
You could use the #XmlPath extension in EclipseLink JAXB (MOXy) to accomplish this use case (I'm the MOXy tech lead):
Root
JAXB requires a single object to unmarshal, we will introduce a class to fulfill this role. This class will have fields corresponding to the two Objects you wish to unmarshal annotated with the self XPath: #XmlPath(".")
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="type")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlPath(".")
private Item item;
#XmlPath(".")
private ItemDimensions itemDimensions;
}
ItemDimensions
You annotate this class normally. In your example you annotate the properties, but only provide getters. This will cause JAXB to think that those are write only mappings.
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class ItemDimensions {
private Integer height;
private Integer width;
private Integer depth;
}
Item
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private Integer id;
private Double cost;
}
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal(new File("input.xml"));
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(o, System.out);
}
}
jaxb.properties
To use MOXy as your JAXB implementation, you must provide a file named jaxb.properties in with your domain objects with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Why doesn't JAXB allow annotations on getters that all pull from the same member variable?

Why does example A work, while example B throws a "JAXB annotation is placed on a method that is not a JAXB property" exception?
I'm using JAX-WS with Spring MVC.
Example A
package com.casanosa2.permissions;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlType(name = "FooXMLMapper")
public class FooXMLMapper implements IFoo {
#XmlElement
private final boolean propA;
#XmlElement
private final boolean propB;
public FooMapper(IFoo foo) {
propA = foo.getPropA()
propB = foo.getPropB()
}
public FooMapper() {
propA = false;
propB = false;
}
#Override
public boolean getPropA() {
return propA;
}
#Override
public boolean getPropB() {
return propB;
}
}
Example B
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlType(name = "FooXMLMapper")
public class FooXMLMapper {
private final IFoo foo;
public FooMapper() {
foo = new IFoo() {
#Override
public boolean getPropA() {
return false;
}
#Override
public boolean getPropB() {
return false;
}
};
}
public FooXMLMapper(IFoo foo) {
this.foo = foo;
}
#XmlElement
public boolean getPropA() {
return foo.getPropA();
}
#XmlElement
public boolean getPropB() {
return foo.getPropB();
}
}
I believe the accessors are ignored if it's looking directly at the instance variables and in your example B there are no actual instance variables of the right name. You have to tell it explicitly to use #XmlAccessorType(XmlAccessType.NONE) on the class and #XmlElement and #XmlAttribute on the get/set methods. At least, that's what I ended up doing with my JAXB mapping.
I believe for it to be a proper JAXB property, you would need setters for them as well as getters. (you would likely need a default constructor as well).
I haven't tried your code yet, but it's example A that looks wrong, not B. In example A you have specified the property accessors (get/set methods) but you have annotated the class fields instead (instance variables).

Mapping Java collections which contains super- and sub-types with JAXB

I'm trying to produce something like this with JAXB:
<person>
<firstName>Foo</firstName>
<lastName>Bar</lastName>
<identities>
<green id="greenId">
<some_elements....
</green>
<blue id="blueId"/>
</identities>
The child elements of <identities> all stem from a common super-class.
In Java it's like this:
#XmlRootElement(name = "person")
public class Person {
public String firstName;
public String lastName;
#XmlElementWrapper(name = "identities")
public Set<Identity> identities = new HashSet<Identity>();
}
Where Identity is a super class for Blue, Green and some others.
public class Identity {
#XmlID
#XmlAttribute
public String id;
}
#XmlRootElement(name = "blue")
public class Blue extends Identity {
public String oneOfManyFields;
}
#XmlRootElement(name = "green")
public class Green extends Identity {}
How do I properly annotate the classes to get what I need? Currently, the output is like so:
<identities>
<identities id="0815"/>
</identities>
Simply modify your example to use the #XmlElementRef annotation on the identities property.
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "person")
public class Person {
public String firstName;
public String lastName;
#XmlElementWrapper(name = "identities")
#XmlElementRef
public Set<Identity> identities = new HashSet<Identity>();
}

Categories