JAXB: unmarshal an XML file with a given XML schema - jaxb

I have a XML file, and its xml schema contains couples complexType in it. So when I unmarshal the xml file, I want to give the xml parser my xml schema. Is it possible to do it, if so, then how to do it?
EDIT: After I unmarshal, every field in my object is null. Any idea why?

UPDATE
The issue you are seeing is due to the content being nested within the NameAndAddress element. You could introduce a NameAndAddress class have PackageLabel hold an instance of that.
PackageLabel
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="PackageLabel")
#XmlAccessorType(XmlAccessType.FIELD)
public class PackageLabel implements Serializable {
#XmlElement(name="NameAndAddress")
private NameAndAddress nameAndAddress;
}
NameAndAddress
import javax.xml.bind.annotation.XmlElement;
public class NameAndAddress {
#XmlElement(name="Name")
private String name;
#XmlElement(name="Address1")
private String address1;
#XmlElement(name="Address2")
private String address2;
#XmlElement(name="City")
private String city;
#XmlElement(name="State")
private String state;
#XmlElement(name="ZipCode")
private String zipCode;
}
EclipseLink JAXB (MOXy)'s #XmlPath Extension
Alternatively you could use the #XmlPath extension in EclipseLink JAXB (MOXy):
import java.io.Serializable;
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="PackageLabel")
#XmlAccessorType(XmlAccessType.FIELD)
public class PackageLabel implements Serializable {
#XmlPath("NameAndAddress/Name/text()")
private String name;
#XmlPath("NameAndAddress/Address1/text()")
private String address1;
#XmlPath("NameAndAddress/Address2/text()")
private String address2;
#XmlPath("NameAndAddress/City/text()")
private String city;
#XmlPath("NameAndAddress/State/text()")
private String state;
#XmlPath("NameAndAddress/ZipCode/text()")
private String zipCode;
}
For More Information
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
You can set an XML schema on an instance of Unmarshaller. This will cause JAXB to validate the input while it converts the XML to objects:
http://bdoughan.blogspot.com/2010/12/jaxb-and-marshalunmarshal-schema.html
If you want to generate an object model from an XML schema, you can also use JAXB to do that:
http://bdoughan.blogspot.com/2010/09/processing-atom-feeds-with-jaxb.html

Related

Why Can't CDI Find My Producer?

For some reason CDI seems unable to inject a string into a WebSocket ServerEndpoint. I am receiving the error Unsatisfied dependencies for type String with qualifiers #HelloMessage. I've included the Producer and ServerEndpoint implementations below. Any ideas? Injection seems to work if I create a custom class (say Messenger) and produce that instead of String.
Qualifier Implementation
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public
#interface HelloMessage
{
}
Producer Implementation
import java.io.Serializable;
import javax.inject.Named;
import javax.ws.rs.Produces;
public
class StringProducer
implements Serializable
{
#Produces
#HelloMessage
public
String getMessage()
{
return "Hello, from Message!";
}
}
ServerEndpoint Implementation
import javax.inject.Inject;
import javax.inject.Named;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/test")
public
class TestEndpoint
{
#OnMessage
public
void onMessage(Session session, String unused)
{
System.out.println(this.message);
}
#Inject #HelloMessage
private String message;
}
I needed to import javax.enterprise.inject.Produces instead of javax.ws.rs.Produces when defining the Producer.
Producer Implementation
import java.io.Serializable;
import javax.inject.Named;
import javax.enterprise.inject.Produces;
public
class StringProducer
implements Serializable
{
#Produces
#HelloMessage
public
String getMessage()
{
return "Hello, from Message!";
}
}

Entity is not a known entity type

I try to make a simple Java EE application in java with JSF and Java EE.
I couldn't deploy the following customer entity:
package ch.uufstellend.onlineshop.model;
import java.io.Serializable;
import javax.ejb.Stateful;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Data
#Table(name = "CUSTOMER")
#NamedQuery(
name = "Customer.findAll",
query = "SELECT c FROM Customer c")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
private String email;
private String password;
public Customer() {
}
#Override
public String toString() {
return id + "-" + email + "-" + password;
}
}
Because of:
Severe: Exception while deploying the app [uuf-onlineshop-ear] :
Invalid ejb jar [uuf-onlineshop-ejb-1.0-SNAPSHOT.jar]: it contains
zero ejb. Note:
A valid ejb jar requires at least one session, entity (1.x/2.x style), or message-driven bean.
EJB3+ entity beans (#Entity) are POJOs and please package them as library jar.
If the jar file contains valid EJBs which are annotated with EJB component level annotations (#Stateless, #Stateful, #MessageDriven,
#Singleton), please check server.log to see whether the annotations were processed properly.
If I add a #Stateful annotation to the entity I'm able to deploy the app.
But when I then access the RegisterController the following exception is thrown while persisting the Customer:
exception:>
javax.servlet.ServletException: java.lang.IllegalArgumentException:
Object:
ch.uufstellend.onlineshop.model.__EJB31_Generated__Customer__Intf___302872188
is not a known entity type. root cause
javax.faces.el.EvaluationException:
java.lang.IllegalArgumentException: Object:
ch.uufstellend.onlineshop.model.__EJB31_Generated__Customer__Intf___302872188
is not a known entity type.
Controller:
package ch.uufstellend.onlineshop;
import ch.uufstellend.onlineshop.model.Customer;
import java.io.Serializable;
import javax.annotation.Resource;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import lombok.Getter;
import lombok.Setter;
#Named
#RequestScoped
public class RegisterController implements Serializable {
private static final long serialVersionUID = 1L;
#PersistenceUnit
private EntityManagerFactory emf;
#Resource
private UserTransaction ut;
#Inject
#Getter
#Setter
private Customer customer;
public String persist() {
try {
ut.begin();
EntityManager entityManager = emf.createEntityManager();
entityManager.persist(customer); // HERE the error is thrown
ut.commit();
FacesMessage m = new FacesMessage("Succesfully registered!", "Your email was saved under id " + customer.getId());
FacesContext.getCurrentInstance().addMessage("registerForm", m);
} catch (NotSupportedException | SystemException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException e) {
e.printStackTrace();
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_WARN, e.getMessage(), e.getCause().getMessage());
FacesContext.getCurrentInstance().addMessage("registerForm", m);
}
return "/register.jsf";
}
}
Any idea where the problem could be?
Your #Entity entity bean is all fine. Don't modify it. Making it an EJB would indeed cause the described exception because the EJB container creates a proxy around the class which in turn isn't recognized as a JPA entity.
Your #Named managed bean is wrong. It is tight coupled with EJB responsibilities (persistence and transaction management). Split off EJB responsibilities into a real #Stateless session bean and have the managed bean invoke it.
#Stateless
public class RegisterService {
#PersistenceContext
private EntityManager entityManager;
public void persist(Customer customer) {
entityManager.persist(customer);
}
}
#Named
#RequestScoped
public class RegisterController {
#Inject
private Customer customer;
#EJB
private RegisterService registerService;
public String submit() {
FacesMessage m;
try {
registerService.persist(customer);
m = new FacesMessage("Succesfully registered!", "Your email was saved under id " + customer.getId());
} catch (Exception e) {
m = new FacesMessage(FacesMessage.SEVERITY_WARN, e.getMessage(), e.getCause().getMessage());
}
FacesContext.getCurrentInstance().addMessage("registerForm", m);
return "/register.jsf";
}
// ...
}
Note that you do not need to manually fiddle with user transactions in the real EJB. Only the #Inject on Customer is kind of weird. I'm not sure what the #Data does, but if it has the same effect as CDI's #Model annotation, then that's OK. Otherwise head off to second link below for concrete examples and more links.
See also:
When is it necessary or convenient to use Spring or EJB3 or all of them together?
JSF Controller, Service and DAO

Line number of individual XML element while unmarshalling using jaxb

I have a class Person with attributes name and address. I display it in a XML. While unmarshalling from XML will it be possible to get line number for name and address separately.
I tried using Locator. But it does not provide individual line numbers.
The EclipseLink JAXB (MOXy) and the JAXB reference implementation each have their own #XmlLocation annotations for supporting this use case. This allows you to store the location on the XML element corresponding to the object as an instance of org.xml.sax.Locator. Since I'm the MOXy lead, I will demonstrate using MOXy:
Person
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlLocation;
import org.xml.sax.Locator;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Person {
#XmlJavaTypeAdapter(value=StringAdapter.class)
String name;
Address address;
#XmlLocation
Locator locator;
}
Address
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlLocation;
import org.xml.sax.Locator;
public class Address {
#XmlJavaTypeAdapter(value=StringAdapter.class)
private String street;
#XmlLocation
Locator locator;
}
StringAdapter
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.persistence.oxm.annotations.XmlLocation;
import org.xml.sax.Locator;
public class StringAdapter extends XmlAdapter<StringAdapter.AdaptedString, String> {
public static class AdaptedString {
#XmlValue
public String value;
#XmlLocation
#XmlTransient
Locator locator;
}
#Override
public String unmarshal(AdaptedString v) throws Exception {
System.out.println(v.value + " " + v.locator.getLineNumber());
return v.value;
}
#Override
public AdaptedString marshal(String v) throws Exception {
AdaptedString adaptedString = new AdaptedString();
adaptedString.value = v;
return adaptedString;
}
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14455596/input.xml");
Person person = (Person) unmarshaller.unmarshal(xml);
System.out.println("Person: " + person.locator.getLineNumber());
System.out.println("Address: " + person.address.locator.getLineNumber());
}
}
Output
Jane Doe 3
1 A Street 5
Person: 2
Address: 4
You could leverage a StAX StreamReaderDelegate and do something like the following:
Demo
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.stream.util.StreamReaderDelegate;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Person.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource source = new StreamSource("src/forum14455596/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
xsr = new StreamReaderDelegate(xsr) {
#Override
public String getLocalName() {
String localName = super.getLocalName();
if(isStartElement()) {
System.out.println(localName + " " + this.getLocation().getLineNumber());
}
return localName;
}
};
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.unmarshal(xsr);
}
}
Person
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Person {
private String name;
private String address;
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<person>
<name>Jane Doe</name>
<address>1 A Street</address>
</person>
Output
person 2
name 3
address 4

How to unmarshal empty element into empty string with JAXB

There is a pseudo code like this:
Alma alma = new Alma();
alma.setKorte(""); //Korte is a string member
marshaller.marshal(alma, stringwriter);
System.out.println(stringwriter.toString());
And it produces the output of (I know this is some kind of trick that the empty element is there, but this is how it works in my system, so someone before me have set this like this):
<alma><korte/></alma>
Which is fine for me. But when I unmarshal it, the empty string is not unmarshalled correctly, but korte will be null. How to make jaxb to unmarshal the empty element into empty string?
I use JDK6 bundled jaxb.
EDIT:
The alma class looks like (name of class is changed, but it is like this):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Alma", propOrder = {
"korte"
})
public class Alma
implements Serializable
{
private final static long serialVersionUID = 100L;
#XmlElement(required = true)
protected String korte;
JAXB implementations should unmarshal empty elements as "" for String properties. The solution will be to upgrade to a newer version of your JAXB implementation that contains this fix.
The example below worked for me using the version of JAXB included in JDK 1.6.0_20 and EcliseLink JAXB (MOXy) 2.3.
Demo
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Alma.class);
String xmlString = "<alma><korte/></alma>";
StringReader xmlReader = new StringReader(xmlString);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Alma alma = (Alma) unmarshaller.unmarshal(xmlReader);
System.out.println(alma.getKorte().length());
}
}
Output
0
Alma
import java.io.Serializable;
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.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
#XmlType(name = "Alma", propOrder = { "korte" })
public class Alma implements Serializable {
private final static long serialVersionUID = 100L;
#XmlElement(required = true)
protected String korte;
public String getKorte() {
return korte;
}
public void setKorte(String korte) {
this.korte = korte;
}
}

Jaxb - umarshaling mixed xml element with value

I have the follwoing xml element:
<FIELD1><COMP VAR="A">text B</COMP> inner text <COMP VAR="B">text B</COMP></FIELD1>
How to annotate this property with JAXB:
protected List<Object> compOrValue;
to have a list of COMP xml elemnts and String values.
Is it possible with JAXB?
Thanks
You can use a combination of #XmlAnyElement and #XmlMixed to achieve this:
import java.util.List;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="FIELD1")
public class Root {
protected List<Object> compOrValue;
#XmlAnyElement
#XmlMixed
public List<Object> getCompOrValue() {
return compOrValue;
}
public void setCompOrValue(List<Object> compOrValue) {
this.compOrValue = compOrValue;
}
}

Resources