MOXy is only marshaling base class members in a collection - java

I have a base class declared something like:
package com.mystuff.surrogates;
import java.io.Serializable;
import java.util.UUID;
public class BaseClass implements Serializable {
private UUID id;
private String name;
public UUID getId() { return this.id; }
public void setId(UUID id) { this.id = id; }
public String getName() { return thisname; }
public void setName(String name) { this.name = name; }
}
And a derived class which looks something like:
package com.mystuff.surrogates;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class DerivedClass extends BaseClass {
private String email;
public String getEmail() { return this.email; }
public void setEmail(String email) { this.email = email; }
}
Finally I have a class which I am trying to return as an object from a RESTful webservice call which includes a collection of BaseClass derived class instances and looks rather like:
package com.mystuff.surrogates;
import java.util.ArrayList;
import java.util.List;
public class Response {
List<BaseClass> objectList;
public List<BaseClass> getObjectList() { return this.objectList; }
public void setObjectList(List<BaseClass> objectList) { this.objectList = objectList; }
public void addObject(BaseClass obj) {
if (this.objectList == null) {
this.objectList = new ArrayList<>();
}
this.objectList.add(obj);
}
}
When marshaling this into either XML or JSON, only the members in the base class are included. How do I get Jersey / MOXy to marshal the entire class instance rather than just the base class members? While I have only shown here one derived class, I have several others I would like to potentially chose from to return in the list, so simply using List<DerivedClass> isn't an option since it would preclude returning any of those other classes in the list.
Other information:
Netbeans 8.0.2
Glassfish 4.1 (locally hosted)
Oracle JDK 8U31 (64 bit Windows)
Java EE 7

You'll need to use #XmlSeeAlso so the other classes are binded.
#XmlSeeAlso({DerivedClass.class})
public class BaseClass {
This may not get you the exact desired result, as the marshalled data will have a reference to the type. For instance with XML, you will see
<objectList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="derivedClass">
and JSON you will see
{"objectList":[{"type":"derivedClass",...
You can have a look at this answer for an idea of how to get rid of the type property if it's undesired.
As far as the JSON is concerned, using Jackson will not have this behavior. You can simply use jersey-media-json-jackson, which Glassfish also comes shipped with (you can add it as a dependency in a provided scope), and just register the JacksonFeature with the application.

Related

Unable to save Node to Neo4j with Spring boot

I am trying to save a node into Neo4j database with Spring boot and getting the following Exception:
java.lang.IllegalArgumentException: Class class com.test.neo4j.model.Company is not a valid entity class. Please check the entity mapping.
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:77) ~[neo4j-ogm-core-3.2.11.jar:3.2.11]
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:51) ~[neo4j-ogm-core-3.2.11.jar:3.2.11]
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:480) ~[neo4j-ogm-core-3.2.11.jar:3.2.11]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_65]
Below is my Entity class:
package com.test.neo4j.model;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
#NodeEntity
public class Company {
#Id
private String id;
private String name;
public Company() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Below is my repository:
package com.test.neo4j.repository;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import com.test.neo4j.model.Company;
public interface CompanyRepository extends Neo4jRepository<Company, String>{
}
I am Autowiring the repo in my service and calling save with it. Now, I have looked up the other answers and made sure of the following:
Package name does not contain any upper case character
Model class has got default constructor
id is explicitly set in the service
Am I missing anything else here?
The Company class is not part of the class scanning initiated at start of the application.
This can have various reasons:
You are using the Spring Data Neo4j auto starter without any special config for package scans. As a result only entity classes in this package and "sub"-packages will get scanned.
You manually configured the SessionFactory bean and the given package does not match the ("sub"-)package your class is in.

Want’s to Marshall different set of POJO fields based on Spring Profile

I have a POJO Deatils having following fields.
1. String Name
2. String Add
3. String Phone
.
For profile ‘x’ first two fields should marshal in XML and for other profile first and last field should marshal in XML.
Note: no field will be null for any profile.
I feel like it would be better to leave the Marshaller alone. It may be tricky to extend and customize the marshaller to fit your needs per Spring profile.
If our goal is to serialize different payloads depending on Spring profile, I'd recommend maybe a converter/factory that takes in the POJO (that has all the fields) and spits out a Data Transfer Object (DTO) for the specific profile.
Perhaps the following could work unless there is another end-goal in mind.
public class Details { ... }
// essentially a marker interface
public interface MyDto {
}
public class DtoA implements MyDto {
private String name;
private String add;
}
public class DtoB implements MyDto {
private String name;
private String phone;
}
public interface DtoConverter {
MyDto convert(Details details);
}
public class DtoConverterA implements DtoConverter { ... }
public class DtoConverterB implements DtoConverter { ... }
#Configuration
public class MyConfiguration {
#Bean
#Profile("a")
public DtoConverter dtoConverterA() {
return new DtoConverterA();
}
#Bean
#Profile("b")
public DtoConverter dtoConverterB() {
return new DtoConverterB();
}
}

override #XmlElement annotation with FIELD accessor type

I have a class with #XmlAccessorType(XmlAccessType.FIELD) annotation, and each private and protected field is annotated with #XmlElement(name='...').
The challenge: I may want to rename one of the xml element names in a later stage. This leads me to the question. Is there a way to override/redefine these annotations, if I create a sub-class ?
I believe that some implementations of JaxB allow for XML configuration to override the annotations. In this case this may actually be possible. Here is an article from Eclipslink explaining how this can be done http://www.eclipse.org/eclipselink/documentation/2.4/solutions/jpatoxml004.htm
In my opinion you can just build an XML configuration for the JaxB file you want to override.
I tried first with the #XmlAccessorType(XmlAccessType.FIELD) and to hide with #XmlTransient. This only works, if you mark the field in the superclass and in the child class with #XmlTransient. But I assume, this is not what you want.
As second approach I've tried with more restrictive #XmlAccessorType(XmlAccessType.PROPERTY) in the superclass and #XmlAccessorType(XmlAccessType.NONE) in the child class. See here my example:
package com.so.example;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/myresource")
public class MyResource {
#GET
#Path("/car")
#Produces(MediaType.APPLICATION_XML)
public Car getCar() {
Car car = new Car();
car.setWheels(4);
return car;
}
#GET
#Path("/suv")
#Produces(MediaType.APPLICATION_XML)
public Suv getSuv() {
Suv suv = new Suv();
List<String> bigWheels = new ArrayList<>();
bigWheels.add("left front wheel");
bigWheels.add("right front wheel");
bigWheels.add("left rear wheel");
bigWheels.add("right rear wheel");
suv.setBigWheels(bigWheels);
return suv;
}
}
Class Car:
package com.so.example;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement
public class Car {
protected Integer wheels;
public Car() {
}
#XmlElement(name = "wheels", nillable = true)
public Integer getWheels() {
return wheels;
}
public void setWheels(Integer wheels) {
this.wheels = wheels;
}
}
Class Suv (Child):
package com.so.example;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class Suv extends Car {
#XmlTransient
private Integer wheels;
private List<String> bigWheels;
public Suv() {
}
#Override
#XmlTransient
public Integer getWheels() {
return wheels;
}
#Override
public void setWheels(Integer wheels) {
this.wheels = wheels;
}
#XmlElement
public List<String> getBigWheels() {
return bigWheels;
}
public void setBigWheels(List<String> bigWheels) {
this.bigWheels = bigWheels;
}
}
One way to "hide" the element wheels of the superclass would be to mark it as "nillable=true" and not use primitive types. In this case, the field wheels will be marshalled to <wheels xsi:nil="true"/>
If it's possible for you to not use the parent class for marshalling and you are only using child classes, you could use the approach described here:
http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html
Also you could use moxy and specify a custom binding:
http://www.eclipse.org/eclipselink/documentation/2.4/moxy/runtime003.htm
Whilst in java, to my knowledge, overriding an annotation #XmlElement(name='...') to change the name property is not possible; you can create a global variable in your code and either pass it through your classes or your functions following the #XmlElement(name='...').
In the code below I created a single class but it contains the setter and getter methods required if you want to pass it through to another class
#XMLAccessorType(XMLAccessType.FIELD)
public class YourClass {
#XmlTransient
private String string = ""; //This can be replaced with whatever variable you are manipulating
//That could be an int or a file or anything really
#XmlElement(name = "your_name")
private void doSomething() {
String temp = getString(); //This variable is normally used to pass between different
//classes but may as well use it if you have one
//Your code which manipulates the String
setString(temp); //This variable is normally used to pass between different classes but
//may as well use it if you have one
}
#XmlElement(name = "your_other_name")
private void doSomethingElse() {
String temp = getString();
//Your code which manipulates the String
setString(temp);
}
public void getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
I would reccomend looking at the Java Docs for #XmlTransient and these two other relevant SO questions.
How to override JAXB #XMLAccessorType(XMLAccessType.FIELD) specified at a Class level with #XMLElement on a getter method for a property?
Jaxb - Overriding the XMLElement name attribute

Not able to annotate a class with #XmlTransient annotation

Below is my code,
Where I am not able to annotate a class with #XmlTransient annotation,
netbeans IDE says annotation type not applicable to this kind of declaration.
I have JDK 1.6 and Jaxb 1.5 running with netbeans.
Thanks for any help.
import com.duncansolutions.databus.external.util.xml.XMLDateAdapter;
import com.duncansolutions.databus.external.xml.parkmobile.PayByCell;
import java.io.Serializable;
import java.util.Date;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlTransient
public class AddTime extends PayByCell implements Serializable{
private Integer transmissionId;
private Integer spaceNumber;
#XmlElement(name = "TransmissionID")
public Integer getTransmissionId() {
return transmissionId;
}
public void setTransmissionId(Integer transmissionId) {
this.transmissionId = transmissionId;
}
#XmlElement(name = "SpaceNumber")
public Integer getSpaceNumber() {
return spaceNumber;
}
public void setSpaceNumber(Integer spaceNumber)
{
this.spaceNumber = spaceNumber;
}
#XmlJavaTypeAdapter(XMLDateAdapter.class)
#XmlElement(name = "StartDateTime")
#Override
public Date getStartTime() {
return startTime;
}
#XmlJavaTypeAdapter(XMLDateAdapter.class)
#XmlElement(name = "EndDateTime")
#Override
public Date getExpTime() {
return expTime;
}
}
#Retention(value=RUNTIME)
#Target(value={FIELD,METHOD})
public #interface XmlTransient
As you can see annotation #XmlTransient only can be applied in FIELDs or METHODS. It is what the API said.
This annotation avoid that a specific member variable will be written in the representation of the object in XML.
http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlTransient.html
According to the documentation, #XmlTransient is only applicable to a field or a method, not a class. This is, of course, from Java EE 5; it seems that in Java EE 6 and newer, you're allowed to do so.
If you want to use it, be sure that you're using a newer Java EE JAR.

Create Null Object Unmarshalling Empty Element with JAXB

I am using JAXB (EclipseLink implementation) in a JAX-RS webservice. When an empty element is passed in the XML request an empty object is created. Is it possible to set JAXB to create a null object instead?
Example XML:
<RootEntity>
<AttributeOne>someText</AttributeOne>
<EntityOne id="objectID" />
<EntityTwo />
</RootEntity>
When unmarshalling, an instance of EntityOne is created and the id attribute set to "objectID" and an instance of EntityTwo is created with null attributes. Instead I would like a null object for EntityTwo as having an empty object is causing me problems with JPA persistence operations.
You can specify this behaviour using MOXy's NullPolicy. You will need to create a DescriptorCustomizer to modify the underlying mappings. Don't worry it's easier than it sounds, I'll demonstrate below:
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
public class RootEntityCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
XMLCompositeObjectMapping entityTwoMapping = (XMLCompositeObjectMapping) descriptor.getMappingForAttributeName("entityTwo");
entityTwoMapping.getNullPolicy().setNullRepresentedByEmptyNode(true);
entityTwoMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE);
}
}
Below is how you associate the customizer with your model class:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlCustomizer;
#XmlRootElement(name="RootEntity")
#XmlCustomizer(RootEntityCustomizer.class)
public class RootEntity {
private String attributeOne;
private Entity entityOne;
private Entity entityTwo;
#XmlElement(name="AttributeOne")
public String getAttributeOne() {
return attributeOne;
}
public void setAttributeOne(String attributeOne) {
this.attributeOne = attributeOne;
}
#XmlElement(name="EntityOne")
public Entity getEntityOne() {
return entityOne;
}
public void setEntityOne(Entity entityOne) {
this.entityOne = entityOne;
}
#XmlElement(name="EntityTwo")
public Entity getEntityTwo() {
return entityTwo;
}
public void setEntityTwo(Entity entityTwo) {
this.entityTwo = entityTwo;
}
}
In the next version of MOXy (2.2) you will be able to do this via annotations.
#XmlElement(name="EntityTwo")
#XmlNullPolicy(emptyNodeRepresentsNull=true,
nullRepresentationForXml=XmlMarshalNullRepresentation.EMPTY_NODE)
public Entity getEntityTwo() {
return entityTwo;
}
You can try this now with one of the EclipseLink 2.2.0 nightly builds:
http://www.eclipse.org/eclipselink/downloads/nightly.php

Categories

Resources