How to remove the element name from xml? - jaxb

I am trying to create a person rest service.And am trying to create xml schema using JAXB and JSon Schema Using Jackson.
So Here is my Model classes to create the respective XML as well as JSon Payload.
package www.tempuri.person.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonRootName;
#ApiModel(value="GetPerson Message",description = "Personal Input Request")
#XmlRootElement(name="getPerson")
#JsonRootName(value = "getPerson")
public class GetPersonWrapper {
#ApiModelProperty(value = "GetPerson", required = true)
private GetPerson getPerson;
public GetPerson getGetPerson() {
return getPerson;
}
public void setGetPerson(GetPerson getPerson) {
this.getPerson = getPerson;
}
}
package www.tempuri.person.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#ApiModel(description = "Represents Persons")
public class GetPerson {
#ApiModelProperty(value = "Application Area of GetPerson", required = true)
private ApplicationArea applicationArea;
#ApiModelProperty(value = "Data Area of GetPerson", required = true)
private DataAreaGet dataArea;
/**
* #return the dataArea
*/
public DataAreaGet getDataArea() {
return dataArea;
}
/**
* #param dataArea the dataArea to set
*/
public void setDataArea(DataAreaGet dataArea) {
this.dataArea = dataArea;
}
public ApplicationArea getApplicationArea() {
return applicationArea;
}
public void setApplicationArea(ApplicationArea applicationArea) {
this.applicationArea = applicationArea;
}
}
With the above model classes, the json schema is coming as intended. But in case of xml i am not able to get what i want to:
Below is the schema that it generated in xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<getPerson>
<getPerson>
<applicationArea/>
<dataArea>
<description>string</description>
<id>0</id>
<name>string</name>
</dataArea>
</getPerson>
</getPerson>
As you can see i am getting two getPerson Node. How can i remove one of the getPerson node using the jaxb annotations only.
I am using apache camel swagger component to create the rest service.
Looking forward to your solutions. Thanks in advance.

I would use XSLT, straight forward , simple and works like a magic.

Related

Ignore xml element while marshalling and include xml element while unmarsalling by using XmlTransient annotation

I am trying to unmarshal an XML into an object that I expect should have a certain field. However, I do not want to marshal that object into an XML that contains it. What I like would be similar to this:
#XmlRootElement(name = "User")
public class User {
#XmlElement(namespace = "http://www.........", required = false)
private String name;
}
While marshalling , am getting below xml,
Current xml output file looks like:
<User xmlns:ns5="http://www......." />
But I don't want this namespace in output file,
Expected looks like below xml output file,
<User />
I tried to use #XmlTransient annotation,
#XmlRootElement(name = "User")
public class User {
#XmlTransient
private String name;
}
Worked successfully while marshalling and got exception while unmarshalling
org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: No descriptor found while unmarshalling element mapped to user name
Any help would be greatly appreciated.
As per my understanding, you would not want to get the namespaces in your XML. Based on my understanding providing the answer here. Hope it helps or at least guides you in the right direction.
I have done something like this:
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#AllArgsConstructor
#XmlRootElement(name = "User")
public class User {
#XmlTransient
#XmlElement(namespace = "http://www.google/test.com", required = false)
private String name;
private String name1;
public void beforeMarshal(Marshaller m) {
//Executed after reading the data but before marshalling to XML. Here you can perform whatever you would like.
name1 = name;
name = null;
}
public void afterUnmarshal(Unmarshaller m, Object parent) {
//Executed after Unmarshalling the data. Here you can perform whatever you would like.
}
}
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import javax.xml.stream.XMLStreamException;
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
User user = new User();
user.setName("Batman");
final JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
final Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(user, System.out);
}
}
This would result in following XML:
<?xml version="1.0" encoding="UTF-8"?>
<User>
<name1>Batman</name1>
</User>
You can perform accordingly whatever you need within the beforeMarshal and afterMarshal if required.

How to set the namespace of marshalled xml using camel jaxb?

For starters, I'm creating some routes using Camel ver 2.15 (in Fuse 6.2.1).
In my route, i'm trying to create a XML from a pojo that was generated using cxf-xjc maven plugin (cxf-xjc read some xsd somewhere then from the xsd, the pojos with jaxb annotations were produced).
The pojos are TempProject and TempProjects.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "",
propOrder = {"ecode", "tempName"}
)
#XmlRootElement(
name = "TempProject"
)
public class TempProject implements Serializable {
#XmlElement(
name = "Ecode",
required = true
)
protected String ecode;
#XmlElement(
name = "TempName",
required = true
)
protected String tempName;
public TempProject() {
}
public String getEcode() {
return this.ecode;
}
public void setEcode(String value) {
this.ecode = value;
}
public String getTempName() {
return this.tempName;
}
public void setTempName(String value) {
this.tempName = value;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "",
propOrder = {"tempProjects"}
)
#XmlRootElement(
name = "TempProjects"
)
public class TempProjects implements Serializable {
#XmlElement(
name = "TempProject",
required = true
)
protected List<TempProject> tempProjects;
public TempProjects() {
}
public List<TempProject> getTempProjects() {
if (this.tempProjects == null) {
this.tempProjects = new ArrayList();
}
return this.tempProjects;
}
}
I can generate the xml using this code:
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{TempProjects.class});
jaxbContext.createMarshaller();
JaxbDataFormat jaxbDataFormat = new JaxbDataFormat(jaxbContext); //import org.apache.camel.converter.jaxb.JaxbDataFormat;
I call
.marshal(jaxbDataFormat)
in my route to effect the marshalling from the pojo to xml.
The generated xml is posted below:
<TempProjects xmlns="http://blah.blah/foo/schema/v2">
<TempProject>
<Ecode>1</Ecode>
<TempName>Tempname1</TempName>
</TempProject>
<TempProject>
<Ecode>2</Ecode>
<TempName>Tempname2</TempName>
</TempProject>
How can i generate a marshalled xml that will have a namespace like this...
<TempProjects xmlns:myprefix="http://blah.blah/foo/schema/v2">
Reason being why I needed a namespaceprefix is because I plan to split the values (e.g. Ecode) in the xml using xpath and I needed a namespaceprefix to do that (thats what ive researched, i might be wrong).
My planned code in my route is
.marshal(jaxbDataFormat)
.split( xpath("/TempProjects/TempProject/Ecode/text()").namespaces(ns1),
new ProjectIdsAggregator()) //the above xpath doesn't work because it doesn't have a namespace prefix
//Namespaces ns1 = new Namespaces("myprefix", "http://blah.blah/foo/schema/v2" );
I looked at jaxbDataFormat.setNamespacePrefixRef("myprefix"), but i got an error (org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: myprefix of type: java.util.Map)
I'm actually quite new in the apache camel routing world, so i might be missing some basic stuff.
You don't need to change your XML at all. It is fine.
With the XML you posted and the Namespace declaration you posted, the following XPath works fine to split the XML (as an example) into two TempProject parts:
xpath("/myprefix:TempProjects/myprefix:TempProject").namespaces(ns1)
Because you declared the XML namespace like this:
Namespaces ns1 = new Namespaces("myprefix", "http://blah.blah/foo/schema/v2" )
Your XPath must use the prefix myprefix for all elements:
/myprefix:TempProjects/myprefix:TempProject

Getting null value while unmarshalling an XML

Can anyone please help me with this JAXB unmarshal issue?
So, this is the file employee.xml I am using:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<parent>
<anotherchild1>Another</anotherchild1>
</parent>
and this is the Parent.java class which has JAXB annotation:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package XMLToObject;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* #author Gauravb
*/
#XmlRootElement
public class Parent {
private String child;
private String anotherchild1;
public String getAnotherChild1() {
return anotherchild1;
}
public void setAnotherChild1(String child) {
this.anotherchild1 = anotherchild1;
}
}
And this is XMLToObject.java file which I am using:
package XMLToObject;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Gauravb
*/
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class XMLToObject {
public static void main(String[] args) {
try {
File file = new File("employee.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Parent.class);
System.out.println("Reading....."+file.getAbsolutePath());
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Parent p = (Parent) jaxbUnmarshaller.unmarshal(file);
//System.out.println("Child:"+p.getChild());
System.out.println("Another Child:"+p.getAnotherChild1());
} catch (JAXBException e) {e.printStackTrace(); }
}
}
Now, my issue is when I run XMLToObject.java file, then I see following:
Reading.....C:\xxxxxx\employee.xml
Another Child:null
So, can anyone please let me know what can be the reason behind the value as null?
Please note:
1. I am a newbie in JAXB
2. I am using Netbeans editor while running the code
3. I do NOT have XSD for the XML and dont want to use any for my learning
4. I do NOT want to use MOXy for now, this is something I will learn next
You have forgot to add #XmlElement annotation in the binding class Parent.java as below
#XmlElement
private String anotherchild1;

JAXB unmarshalling object in object

I cant unmarshall xml because don't understand how to annotate object class in the another object. Please help.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<ODZ xmlns="http://www.company.com/1.0" >
<Data DataID="ZZZ">
<UserData UserKey="user_001">
<UserEvent>...</UserEvent>
</UserData>
</Data>
</ODZ>
Container classes:
I. First level with link to the second (ODZ -> Data).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "ODZ", namespace = "http://www.company.com/1.0")
public class ODZContainer {
private ImportContainer importContainer;
#XmlElement (name = "Data", type=ImportContainer.class)
public ImportContainer getImportContainer() {
return importContainer;
}
}
II. Second level with link to the third level(Data -> UserData).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "Data")
public class ImportContainer {
private String DataID;
private ArrayList<UserDataBean> userDataBean;
#XmlElement (name = "UserData", type=UserDataBean.class)
public ArrayList<UserDataBean> getUserDataBean() {
return userDataBean;
}
#XmlAttribute(name = "DataID")
public String getDataID() {
return DataID;
}
}
III. Third level with link to the fourth level(UserData-> UserEvent).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "UserData")
public class UserDataBean {
private ArrayList<UserEventBean> userEventData;
private String userEventID;
#XmlAttribute(name = "UserKey")
public String getUserEventID() {
return userEventID;
}
#XmlElement (name = "UserEvent", type=UserEventBean.class)
public ArrayList<UserEventBean> getUserEventBean() {
return userEventData;
}
}
The namespace qualification in your JAXB metadata does not match your XML. You can use the package level #XmlSchema annotation to specify the namespace qualification for your model.
#XmlSchema(
namespace = "http://www.company.com/1.0",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information on JAXB and Namespaces
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Notes About Your Metadata
Since the type of the ArrayList is already specified, you don't need to specify it via the #XmlElement annotation. It doesn't hurt, but its not necessary.
#XmlElement (name = "UserData", type=UserDataBean.class)
public ArrayList<UserDataBean> getUserDataBean() {
return userDataBean;
}
#XmlAccessorType(XmlAccessType.NONE) means that nothing is mapped unless it is explicitly annotated. This may or not be what you want. You may find the following article useful:
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html

Spring LDAP Template Usage

Please take a look at the test class below. I am trying to do an LDAP search with Spring LDAP Template. I am able to search and produce a list of entries corresponding to the search criteria without the Spring LDAP template by using the DirContext as shown in the method searchWithoutTemplate(). But when I use a LdapTemplate, I end up with a NPE as shown further below. I am sure I must be missing something. Can someone help please?
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
import org.springframework.ldap.core.support.LdapContextSource;
public class LDAPSearchTest {
//bind params
static String url="ldap://<IP>:<PORT>";
static String userName="cn=Directory Manager";
static String password="password123";
static String bindDN="dc=XXX,dc=com";
//search params
static String base = "ou=StandardUser,ou=XXXCustomers,ou=People,dc=XXX,dc=com";
static String filter = "(objectClass=*)";
static String[] attributeFilter = { "cn", "uid" };
static SearchControls sc = new SearchControls();
public static void main(String[] args) throws Exception {
// sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
sc.setReturningAttributes(attributeFilter);
searchWithTemplate(); //NPE
//searchWithoutTemplate(); //works fine
}
public static void searchWithTemplate() throws Exception {
DefaultDirObjectFactory factory = new DefaultDirObjectFactory();
LdapContextSource cs = new LdapContextSource();
cs.setUrl(url);
cs.setUserDn(userName);
cs.setPassword(password);
cs.setBase(bindDN);
cs.setDirObjectFactory(factory.getClass ());
LdapTemplate template = new LdapTemplate(cs);
template.afterPropertiesSet();
System.out.println((template.search(new LdapName(base), filter, sc,
new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs)
throws NamingException {
System.out.println(attrs);
return attrs.get("uid").get();
}
})));
}
public static void searchWithoutTemplate() throws NamingException{
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
//env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, userName);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext dctx = new InitialDirContext(env);
NamingEnumeration results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
System.out.println(attrs);
Attribute attr = attrs.get("uid");
}
dctx.close();
}
}
Exception is:
Exception in thread "main" java.lang.NullPointerException
at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:125)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:287)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:237)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:588)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:546)
at LDAPSearchTest.searchWithTemplate(LDAPSearchTest.java:47)
at LDAPSearchTest.main(LDAPSearchTest.java:33)
I am using Spring 2.5.6 and Spring LDAP 1.3.0
A quick scan showed that it's the authenticationSource field of AbstractContextSource that is the culprit. That file includes the following comment on the afterPropertiesSet() method:
/**
* Checks that all necessary data is set and that there is no compatibility
* issues, after which the instance is initialized. Note that you need to
* call this method explicitly after setting all desired properties if using
* the class outside of a Spring Context.
*/
public void afterPropertiesSet() throws Exception {
...
}
That method then goes on to create an appropriate authenticationSource if you haven't provided one.
As your test code above is most definitely not running within a Spring context, and you haven't explicitly set an authenticationSource, I think you need to edit your code as follows:
...
cs.setDirObjectFactory(factory.getClass ());
// Allow Spring to configure the Context Source:
cs.afterPropertiesSet();
LdapTemplate template = new LdapTemplate(cs);

Resources