JAXB/MOXy: How to partially unmarshall, passing the descendants of a given node to a closed/proprietary class? - jaxb

I'm starting with some Java classes that I would like to be able to unmarshall from XML--I'm determining the schema as I go. I would like to use XML similar to the following:
<Person fname="John" lname="Doe">
<bio><foo xmlns="http://proprietary.foo">Blah <bar>blah</bar> blah</foo></bio>
</Person>
I'm hoping to annontate my Java classes similar to the following:
public class Person {
#XmlAttribute
public String fname;
#XmlAttribute
public String lname;
#XmlElement
public ProprietaryFoo bio;
}
I'd like to pass the <foo xmlns="http://proprietary.foo"> element and it's descendants to a compiled factory class which works like this:
FooFactory.getFooFromDomNode(myFooElement) // Returns a private ProprietaryFooImpl as an instance of the public ProprietaryFoo Interface
It seems like I need to create a DomHandler for ProprietaryFoo but I'm not quite able to figure it out (I was getting “com.xyz.ProprietaryFooImpl nor any of its super class is known to this context.") I'm also interested in XmlJavaTypeAdapter I can't figure out how to receive the ValueType as an Element.

Ended up using both an XmlAdapter and a DomHandler along with a simple Wrapper class.
public class FooWrapper {
#XmlAnyElement(FooDomHandler.class)
public ProprietaryFoo foo;
}
public class FooXmlAdapter extends XmlAdapter<FooWrapper, ProprietaryFoo> {
#Override
public ProprietaryFoo unmarshal(FooWrapper w) throws Exception {
return w.foo;
}
#Override
public FooWrapper marshal(ProprietaryFoo f) throws Exception {
FooWrapper fooWrapper = new FooWrapper();
fooWrapper.foo = f;
return fooWrapper;
}
}
/* The vendor also provides a ProprietaryFooResult class that extends SAXResult */
public class FooDomHandler implements DomHandler<ProprietaryFoo, ProprietaryFooResult> {
#Override
public ProprietaryFooResult createUnmarshaller(ValidationEventHandler validationEventHandler) {
return new ProprietaryFooResult();
}
#Override
public ProprietaryFoo getElement(ProprietaryFooResult r) {
return r.getProprietaryFoo();
}
#Override
public Source marshal(ProprietaryFoo f, ValidationEventHandler validationEventHandler) {
return f.asSaxSource();
}
}
For whatever reason, this didn't work with the standard classes from the com.sun namespace but MOXy handles it well.

Related

JHipster EntityMapper interface (mapstruct): map a Spring projection interface

I've generated a new project with JHipster v4.6.0 generator and I'm using its EntityMapper interface to do the mapping between domain and DTO objects.
public interface EntityMapper <D, E> {
public E toEntity(D dto);
public D toDto(E entity);
public List <E> toEntity(List<D> dtoList);
public List <D> toDto(List<E> entityList);
}
I need to use the Spring projection to have a smaller domain and DTO objects, (I don't want all fields of the entity), so I've created an interface with only the getters of the fields I need, and I've created a method in the repository which retrive this interface type (following the Spring reference guide)
public interface ClienteIdENome {
Long getId();
String getNome();
}
#Repository
public interface ClienteRepository extends JpaRepository<Cliente,Long> {
ClienteIdENome findById(Long id);
}
The query findById retrieve a ClienteIdENome object with only id and nome fields.
Now, I would like to map this object in the following DTO:
public class ClienteIdENomeDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
#NotNull
#Size(max = 50)
private String nome;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
So, I created the mapper interface:
#Mapper(componentModel = "spring", uses = {})
public interface ClienteIdENomeMapper extends EntityMapper<ClienteIdENomeDTO, ClienteIdENome> {
}
But Eclipse report to me an error in the EntityMapper interface for the method "public E toEntity(D dto)" with the message:
No implementation type is registered for return type it.andrea.ztest01.repository.ClienteIdENome.
Any help?
Thanks a lot
Your ClienteIdENome is not really an entity. I would argue that you don't need to use the EntityMapper, but you need to define a one way mapper. From ClienteIdENome to ClienteIdENomeDTO.
Your mapper needs to look like:
public interface ClienteIdENomeMapper {
ClienteIdENomeDTO toDto(ClienteIdENome entity);
List <ClienteIdENomeDTO> toDto(List<ClienteIdENome> entityList);
}
I don't know JHipster, so I can't say what will mean using a mapper different than EntityMapper.

Map to specific derived type based on value on source using Automapper

I'm having trouble implementing Automapper conversion in a situation where the source is a class which should be mapped to one of two derived classes based on a value on the source.
Here's a simplification of my classes:
public class FooContainerDTO
{
public FooDTO Foo { get; set; }
}
public class FooDTO
{
public string Type { get; set; }
//some properties..
}
public class FooContainer
{
public FooBase Foo { get; set; }
}
public abastract class FooBase
{
//some properties..
}
public class FooDerived1 : FooBase
{
//some properties
}
public class FooDerived2 : FooBase
{
//some properties
}
I'm using non-static Automapper so I create a MapperConfiguration from several Profiles at boot and inject the IMapper instance into my DI-container.
I want Automapper to map FooDTO to FooDerived1 when its Type property is "der1" and to FooDerived2 when it is "der2".
I've seen examples on this using the static api, something like this:
Mapper.CreateMap<FooContainerDTO, FooContainer>();
//ForMember configurations etc.
Mapper.CreateMap<FooDTO, FooDerived1>();
//ForMember configurations etc.
Mapper.CreateMap<FooDTO, FooDerived2>();
//ForMember configurations etc.
Mapper.CreateMap<FooDTO, FooBase>()
.ConvertUsing(dto => dto.Type == "der1"
? (FooBase) Mapper.Map<FooDerived1>(dto)
: Mapper.Map<FooDerived2>(dto));
This would map the Foo property of FooContainer to the correct derived type of FooBase.
But how can I do this without the static API?
The IMapper instance is not yet created at the point of configuring the profile.
Is there a way to leverage the overload of ConvertUsing() which takes a Func< ResolutionContext,object >? Can the resolution context give me whatever IMapper is currently being used? I've been looking, but can't find anything usable.
One way to get access to the mapping engine is via your own TypeConverter
abstract class MyTypeConverter<TSource,TDestination> : ITypeConverter<TSource, TDestination>
{
protected ResolutionContext context;
public TDestination Convert(ResolutionContext context)
{
this.context = context;
return Convert((TSource)context.SourceValue);
}
public abstract TDestination Convert(TSource source);
}
You then create an actual implementation like:
class MyTypeMapper : MyTypeConverter<EnumType,EnumTypeView>
{
public override EnumTypeView Convert(EnumType source)
{
return context.Engine.Mapper.Map<EnumTypeID, EnumTypeView>(source.EnumBaseType);
}
}
Except instead of unwrapping an enum structure, you'd check the type and call Map with different types.

Trying Decorator Design Pattern, what's wrong with this code?

I have this code that explains the decorator pattern:
public abstract class IBeverage {
protected string description = "Unknown beverage";
public virtual string getDescription() {
return description;
}
}
public abstract class CondimentDecorator : IBeverage {
public abstract string getDescription();
}
public class Espresso : IBeverage {
public Espresso() {
description = "Espresso";
}
}
public class Mocha : CondimentDecorator {
IBeverage beverage;
public Mocha(IBeverage beverage) {
this.beverage = beverage;
}
public override string getDescription() {
return beverage.getDescription() + ", Mocha";
}
}
I should use it like:
static void Main(string[] args) {
IBeverage b = new Espresso();
Console.WriteLine(b.getDescription());
b = new Mocha(b);
Console.WriteLine(b.getDescription());
Console.ReadKey();
}
When I create the beverage (Beverage b = new Espresso();) _description is updated to "Espresso", when I decorate b with Mocha (b = new Mocha(b)), then _description takes the original value "Unknown Beverage". It should be "Espresso, Mocha". What's wrong?
This code was originally written in Java (the book was written with Java), but I translated it into C#. I guess Java works a little different from C#.
Because GetDescription() is not virtual.
public virtual string GetDescription() { ... }
virtual is the companion keyword to override, it's what allows subclasses to override methods. This is a key difference in C# from Java. In Java all methods are implicitly virtual.
You've actually got a few issues here (perhaps differing designs from Java). Even after sorting all of the naming issues, you will not get what you expect.
public abstract class CondimentDecorator : IBeverage {
public abstract string GetDescription();
}
The CondimentDecorator class will actually hide the IBeverage version GetDescription() method (you technically should use public new abstract string GetDescription();.
You are classifying the Mocha class as an IBeverage by assigning it to the b variable (which you earlier defined as an IBeverage via IBeverage b = new Espresso(), the IBeverage version of the GetDescription() method is what actually fires (totally ignoring the Mocha override of the CondimentDecorator GetDescription() method)
You can see this if you step through the code. Try using
CondimentDecorator m = new Mocha(b);
Console.WriteLine(m.GetDescription());
and you will get what you expect.
However, this kind of defeats the purpose of using a decorator in my opinion. A better option would be to change the design a bit and get rid of the CondimentDecorator. It is not providing anything other than confusion and unexpected behaviour. Instead try this:
This is your only needed abstract Beverage class:
public abstract class Beverage
{
// c# convention is to use properties instead of public fields.
// In this case I've used a private readonly backing field.
private readonly string _description = "Unknown Beverage";
protected string Description
{
get { return _description; }
set { _description = value; }
}
// Make this method virtual so you can override it, but if you
// choose not to, this is the default behaviour.
public virtual string GetDescription()
{
return Description;
}
}
This is a standard beverage class (can be decorated):
public class Espresso : Beverage
{
public Espresso()
{
// Setting the Beverage class Description property.
// You can use base.Description if you prefer to be explicit
Description = "Espresso";
}
}
This is a Beverage class that decorates another Beverage class:
public class Mocha : Beverage
{
// store an instance of the Beverage class to be decorated
private readonly Beverage _beverage;
// Beverage instance to be decorated is passed in via constructor
public Mocha(Beverage beverage)
{
_beverage = beverage;
}
// Override Beverage.GetDescription
public override string GetDescription()
{
// Calls decorated Beverage's GetDescription and appends to it.
return _beverage.GetDescription() + ", Mocha";
}
}
And now to get the behaviour you expect, you can run the same code as above:
static void Main(string[] args)
{
Beverage b = new Espresso();
Console.WriteLine(b.getDescription()); // "Espresso"
b = new Mocha(b);
Console.WriteLine(b.getDescription()); // "Espresso, Mocha"
Console.ReadKey();
}
As a side note. You can avoid using Console.ReadKey(); when debugging by using Ctrl + F5 This will automatically put in "Press any key to continue..." for you.
UPDATE
Since you want to include the CondimentDecorator class (as mentioned in your comment), you can create the following class:
public abstract class CondimentDecorator : Beverage
{
private readonly Beverage _beverage;
protected Beverage Bevy
{
get { return _beverage; }
}
protected CondimentDecorator(Beverage beverage)
{
_beverage = beverage;
}
}
Then you would change your Mocha class to the following:
// override CondimentDecorator instead of Beverage
public class Mocha : CondimentDecorator
{
// Pass the Beverage to be decorated to the base constructor
// (CondimentDecorator)
public Mocha(Beverage beverage)
: base(beverage)
{
// nothing needed in this constructor
}
public override string GetDescription()
{
// Now access the CondimentDecorator's Beverage property
// (which I called Bevy to differentiate it)
return Bevy.GetDescription() + ", Mocha";
}
}

Creating xml from JAXB when one value is retrieved using a factory method

I have a UUID class where I get the uuid from a static factory method like
UUIDGenerator.getInstance().getUuid();
I have another class which has these UUids as a list.
class Artifact
{
Uuid uuid;
setUuid(Uuid uuid)
{
this.uuid = uuid;
}
Uuid getUuid()
{
return this.uuid;
}
}
Class ArtifactData
{
private List<Artifact> artifacts;
//setter for list
// getter for list
}
I want the xml to be created as
<ArtifactData>
<AssociatedArtifactList>
<ArtifactUuid>#some value<ArtifactUuid>
</AssociatedArtifactList>
</ArtifactData>
How do I create this xml out of Jaxb annotations. It complains on saying there isn't a public constructor for Uuid because it is constructed out of a factory method.
EDIT: The Uuid and Uuid generator cannot be modified. They are in a JAR. This is what I have tried so far
public class Artifact
{
#XmlJavaTypeAdapter(ArtifactUuidAdapter.class)
private Uuid uuid;
public Uuid getUuid()
{
return uuid;
}
public void setUuid(Uuid uuid)
{
this.uuid = uuid;
}
}
#XmlRootElement
public class ArtifactData
{
private List<Artifact> associatedArtifactList;
public List<Artifact> getArtifacts()
{
return associatedArtifactList;
}
#XmlElementWrapper(name="associatedArtifactList")
#XmlElement(name = "artifactUuid")
public void setArtifacts(List<Artifact> artifacts)
{
this.associatedArtifactList = artifacts;
}
}
public class ArtifactUuidAdapter extends XmlAdapter<Uuid, String>
{
#Override
public Uuid marshal(String uuid) throws Exception
{
return Uuid.getInstance(uuid);
}
#Override
public String unmarshal(Uuid uuid) throws Exception
{
return uuid.getData();
}
}
I still get an error called no arg default constructor is missing.
The #XmlType annotation allows you to configure a factory class and method. The factory class described in your questions doesn't quite meet the API requirements but you could easily create an adapter for it.
UUIDGeneratorAdapter
The class below would adapt your factory class to something that a JAXB (JSR-222) implementation could leverage.
public class UUIDGeneratorAdapter {
public static Uuid getUuid() {
return UUIDGenerator.getInstance().getUuid();
}
}
Uuid
Below is an example of how you configure the factory class through the #XmlType annotation.
import javax.xml.bind.annotation.XmlType;
#XmlType(factoryClass=UUIDGeneratorWrapper.class, factoryMethod="getUuid")
public class Uuid {
// ...
}
For More Information
http://blog.bdoughan.com/2011/06/jaxb-and-factory-methods.html

MOXy JAXB: how to map several XML tag elements to the same JAVA bean property

I am trying to unmarshall an XML file using MOXy JAXB. I have a set of classes, already generated, and I am using Xpath to map every XML element I need into my model.
I have an XML file like this:
<?xml version="1.0" encoding="UTF-8"?>
<fe:Facturae xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:fe="http://www.facturae.es/Facturae/2009/v3.2/Facturae">
<Parties>
<SellerParty>
<LegalEntity>
<CorporateName>Company Comp SA</CorporateName>
<TradeName>Comp</TradeName>
<ContactDetails>
<Telephone>917776665</Telephone>
<TeleFax>917776666</TeleFax>
<WebAddress>www.facturae.es</WebAddress>
<ElectronicMail>facturae#mityc.es</ElectronicMail>
<ContactPersons>Fernando</ContactPersons>
<CnoCnae>28000</CnoCnae>
<INETownCode>2134AAB</INETownCode>
<AdditionalContactDetails>Otros datos</AdditionalContactDetails>
</ContactDetails>
</LegalEntity>
</SellerParty>
<BuyerParty>
<Individual>
<Name>Juana</Name>
<FirstSurname>Mauriño</FirstSurname>
<OverseasAddress>
<Address>Juncal 1315</Address>
<PostCodeAndTown>00000 Buenos Aires</PostCodeAndTown>
<Province>Capital Federal</Province>
<CountryCode>ARG</CountryCode>
</OverseasAddress>
<ContactDetails>
<Telephone>00547775554</Telephone>
<TeleFax>00547775555</TeleFax>
</ContactDetails>
</Individual>
</BuyerParty>
</Parties>
</fe:Facturae>
Then I have my model:
#XmlRootElement(namespace="http://www.facturae.es/Facturae/2009/v3.2/Facturae", name="Facturae")
public class Facturae implements BaseObject, SecuredObject, CreationDataAware {
#XmlPath("Parties/SellerParty")
private Party sellerParty;
#XmlPath("Parties/BuyerParty")
private Party buyerParty;
}
public class Party implements BaseObject, SecuredObject, CreationDataAware {
#XmlPath("LegalEntity/ContactDetails")
private ContactDetails contactDetails;
}
As you can see, <ContactDetails></ContactDetails> is present in <SellerParty></SellerParty> and <BuyerParty></BuyerParty> but this two tags share the same JAVA object (Party). With the previous mapping (#XmlPath("LegalEntity/ContactDetails")) I can pass correctly the ContactDetails info in SellerParty, but I want also to pass the ContactDetails in <BuyerParty> at the same time.
I was trying something like that:
#XmlPaths(value = { #XmlPath("LegalEntity/ContactDetails"),#XmlPath("Individual/ContactDetails") })
private ContactDetails contactDetails;
but it doesn't work.
Can you guys give me a hand?
Thank you very much.
You could use an XmlAdapter for this use case:
PartyAdapter
We will use an XmlAdapter to convert an instance of Party to another type of object AdaptedParty. AdaptedParty will have two properties corresponding to each property in Party (one for each mapping possibility). We will take advantage of the ability to pre-initialize an instance of XmlAdapter to set an instance of Facturae on it. We will use the instance of Facturae to determine if the instance of Party we are handling is a sellerParty or a buyerParty.
package forum9807536;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;
public class PartyAdapter extends XmlAdapter<PartyAdapter.AdaptedParty, Party> {
private Facturae facturae;
public PartyAdapter() {
}
public PartyAdapter(Facturae facturae) {
this.facturae = facturae;
}
#Override
public Party unmarshal(AdaptedParty v) throws Exception {
Party party = new Party();
if(v.individualName != null) {
party.setName(v.individualName);
party.setContactDetails(v.individualContactDetails);
} else {
party.setName(v.sellPartyName);
party.setContactDetails(v.sellerPartyContactDetails);
}
return party;
}
#Override
public AdaptedParty marshal(Party v) throws Exception {
AdaptedParty adaptedParty = new AdaptedParty();
if(null == facturae || facturae.getSellerParty() == v) {
adaptedParty.sellPartyName = v.getName();
adaptedParty.sellerPartyContactDetails = v.getContactDetails();
} else {
adaptedParty.individualName = v.getName();
adaptedParty.individualContactDetails = v.getContactDetails();
}
return adaptedParty;
}
public static class AdaptedParty {
#XmlPath("Individual/Name/text()")
public String individualName;
#XmlPath("Individual/ContactDetails")
public ContactDetails individualContactDetails;
#XmlPath("LegalEntity/CorporateName/text()")
public String sellPartyName;
#XmlPath("LegalEntity/ContactDetails")
public ContactDetails sellerPartyContactDetails;
}
}
Party
We will use the #XmlJavaTypeAdapter to associate the PartyAdapter to the Party class:
package forum9807536;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlJavaTypeAdapter(PartyAdapter.class)
public class Party implements BaseObject, SecuredObject, CreationDataAware {
private String name;
private ContactDetails contactDetails;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ContactDetails getContactDetails() {
return contactDetails;
}
public void setContactDetails(ContactDetails contactDetails) {
this.contactDetails = contactDetails;
}
}
Demo
The following demo code demonstrates how to set a pre-initialized XmlAdapter on the Marshaller:
package forum9807536;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Facturae.class);
File xml = new File("src/forum9807536/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Facturae facturae = (Facturae) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setAdapter(new PartyAdapter(facturae));
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(facturae, System.out);
}
}
Output
Below is the output from the demo code that corresponds to the portion of your model that I have mapped.
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Facturae xmlns:ns0="http://www.facturae.es/Facturae/2009/v3.2/Facturae">
<Parties>
<BuyerParty>
<Individual>
<Name>Juana</Name>
<ContactDetails/>
</Individual>
</BuyerParty>
<SellerParty>
<LegalEntity>
<CorporateName>Company Comp SA</CorporateName>
<ContactDetails/>
</LegalEntity>
</SellerParty>
</Parties>
</ns0:Facturae>
For More Information
http://blog.bdoughan.com/search/label/XmlAdapter
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Resources