Can I replace jaxb.properties with code? - java

I am using some non-standard extensions from EclipseLink's implementation of JAXB, and to enable that implementation, I have to configure it using jaxb.properties. Works well.
However, due to a build error, the properties file was not included in the proper place, resulting in the default JAXB being used, which without any errors just continued to parse the XML file, ignoring the non-standard extension, leaving me with a non-working bean.
To make this more robust, I'd like to get rid off the properties file and specify the context configuration in code. I already have a compile-time dependency on EclipseLink because of their annotations, and I do not need this part configurable at deploy time (in fact, seeing what can go wrong, I do not want it configurable).

You could do the following to get an EclipseLink JAXB (MOXy) JAXBContext without a jaxb.properties file:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
//JAXBContext jc = JAXBContext.newInstance(Animals.class);
JAXBContext jc = JAXBContextFactory.createContext(new Class[] {Animals.class}, null);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum6871469/input.xml");
Animals animals = (Animals) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(animals, System.out);
}
}

Related

How to stop JAXB from escaping certain characters when converting java class to XML String? [duplicate]

This question already has answers here:
How to generate CDATA block using JAXB?
(10 answers)
JAXB Marshalling Unmarshalling with CDATA
(7 answers)
Closed 2 years ago.
I have run into a few issues in my Java 1.8 application when trying to use JAXB to marshal my Java object into an XML string. The first issue was that by default marshalling escapes < and > so when i was trying to wrap some fields in
<![CDATA[ my-field-value ]]>
it was being turned into
<![CDATA[ my-field-value ]]>
Which breaks functionality of using CDATA in the first place. I used a custom character handler according to some comments from How to prevent JAXB escaping a string. Everything is working for me now but i have heard that im not supposed to use com.sun.xml.internal.* packages and currently I am doing so like this (notice the use of internal):
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
JAXBContext jc = JAXBContext.newInstance(MyClass.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(
"com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
new MyCustomCharacterHandler());
return marshaller;
Where MyCustomCharacterHandler is declared like so (note the use of internal):
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
public class XmlCdataCharacterHandler implements CharacterEscapeHandler {
...
}
This combination is working fine for me but when modifying my code to get rid of .internal.* like so using this dependency:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.7</version>
</dependency>
import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
public class XmlCdataCharacterHandler implements CharacterEscapeHandler {
...
}
JAXBContext jc = JAXBContext.newInstance(PrintPack.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(
"com.sun.xml.bind.marshaller.CharacterEscapeHandler",
new MyCustomCharacterHandler());
return marshaller;
My server will no longer start and is getting a JAXBException with the following message:
name: com.sun.xml.bind.marshaller.CharacterEscapeHandler value: com.fmrco.research.search.handlers.MyCustomCharacterHandler#1f3d4305
Which makes me think that my custom handler which implements the CharacterEscapeHandler is no longer being used correctly. Does anyone know how to fix this so i can keep this implementation while avoiding com.sun.xml.internal.* packages? Is there a better/newer way to turn a java class into an XML string? Seems like I should not be stuck on this for as long as I have been. Thank you!

MOXy dependency on org.glassfish.json.JsonProviderImpl? And another question

I'm trying to do something which I thought was pretty simple, which is to use JSON for persisting a POJO container with various properties in it.
After reading up about various ways to marshal/unmarshal JSON without all the web services stuff on top, I figured MOXy would be the best way as it seems to be able to handle non-JAXB annotated POJOs. I'm using MOXy 2.7.3.
However, I ran into two issues:
I'm using Maven with the following dependency:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.7.3</version>
</dependency>
However, if I don't also include this dependency on a GlassFish JAR:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
I get the following exception when attempting to unmarshal (marshaling works fine):
Caused by: Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: javax.json.JsonException: Provider org.glassfish.json.JsonProviderImpl not found
at org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalException(XMLMarshalException.java:122)
at org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader.parse(JsonStructureReader.java:148)
...
Why does MOXy need the GlassFish JsonProviderImpl dependency?
I need to declare an #XmlRootElement in my container class. Not sure why, but this is the case even if I use marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);, which seems to be the default. If I don't don't have an #XmlRootElement I get the following exception when trying to unmarshal (marshaling works fine):
Caused by: Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element stringValue was not found in the project
Maybe I'm just confused, but it seemed like from the docs that MOXy was able to work with POJOs?
Here is some example code showing what I'm doing:
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Paths;
import java.time.ZonedDateTime;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.MarshallerProperties;
public class MoxyTest
{
public static void main(String[] args) throws Exception
{
// Create an instance of the container to be written/read with JSON
TestContainer testContainer = new TestContainer();
testContainer.stringValue = "test string";
testContainer.intValue = 5;
testContainer.zonedDateTimeValue = ZonedDateTime.now().minusMonths(1);
// Note that JAXBContextFactory is specific to MOXy, this was done to avoid having to create a jaxb.properties
// See https://stackoverflow.com/questions/6963996/can-i-replace-jaxb-properties-with-code and
// https://stackoverflow.com/questions/28676613/set-moxy-as-jaxb-provider-without-properties-file-in-the-same-package
JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {TestContainer.class}, null);
Marshaller marshaller = jaxbContext.createMarshaller();
// By default the marshaller will output XML, we have to tell it to use JSON instead
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
File dataFile = Paths.get("/temp", "datafile.json").toFile();
Writer writer = new FileWriter(dataFile);
marshaller.marshal(testContainer, writer);
writer.close();
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// By default the unmarshaller will try to read XML, we have to tell it to use JSON instead
unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
// Determine the location for the file which is used to persist the data
if (dataFile.exists() && (dataFile.length() > 0))
{
Reader reader = new FileReader(dataFile);
TestContainer readTestContainer = (TestContainer) unmarshaller.unmarshal(reader);
System.out.println(readTestContainer.intValue);
System.out.println(readTestContainer.stringValue);
System.out.println(readTestContainer.zonedDateTimeValue);
reader.close();
}
}
}
And the test container (with #XmlRootElement):
import java.time.ZonedDateTime;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "testContainer")
public class TestContainer
{
public String stringValue;
public int intValue;
public ZonedDateTime zonedDateTimeValue;
}
Note that for extra awesomeness, maybe someone can answer why ZonedDateTime will properly marshal but not unmarshal (result is null)? Here are the results from running MoxyTest:
5
test string
null

JAXBException : no package name is given

for XML File parsing I am using JAXB but after compilation following error is reported
javax.xml.bind.JAXBException: No package name is given
at javax.xml.bind.ContextFinder.find(Unknown Source)
at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
at javax.xml.bind.JAXBContext.newInstance(Unknown Source)
at searchAlgo.Question.<init>(Question.java:16)
code is given below
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class Question {
//String question = new String() ;
String s = new String();
Question()
{
try{
File file = new File("C:\\Users\\Username\\Documents\\levels.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(s);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
String string = (String) jaxbUnmarshaller.unmarshal(file);
System.out.println(string);
}
catch(JAXBException e){
e.printStackTrace();
}
}}
do I need to install JAXB plug-in?
i am using jdk 1.8.0_91 and eclipse mars
Your problem is that you're not using JAXB correctly.
First,
JAXBContext jaxbContext = JAXBContext.newInstance(s);
is wrong because JAXBContext.newInstance(...) is expecting either a class or " separated java package names that contain schema-derived classes and/or fully qualified JAXB-annotated classes" according to documentation
The point is to determine what kind of objects JAXB is dealing with. In other words, it will be what kind of objects you have inside C:\\Users\\Username\\Documents\\levels.xml XML file.
Second,
if you want to unmarshall objects from XML file or marshall objects to String, I suggest you read the following documentation with a lot of examples:
Marshaller
Unmarshaller
JAXBContext.newInstance() expects either a Class or a package name. Since s is a String, it is interpreted as a package name. But your String is empty, so you get "No package name is given"

how to use jaxb to create java objects

I am trying to create java objects from xml file. I am using jaxb(unmarshalling) to create java objects.I am getting errors javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/2001/XMLSchema", local:"schema"). Expected elements are
I did some google and found out that, we need xsd file to do that... so I converted it to xsd using apache inst2xsd tool. I am using following java code:
import java.io.FileNotFoundException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="report")
public class Report
{
public static void main(String [] args) throws FileNotFoundException
{
try
{
JAXBContext jc = JAXBContext.newInstance(new Class[] {com.bcbsks.testjb.Report.class});
Unmarshaller um = jc.createUnmarshaller();
Report myJAXBObject = (Report)um.unmarshal(new java.io.FileInputStream("report.xsd"));
}
catch( UnmarshalException ue )
{
ue.printStackTrace();
}
catch( JAXBException je )
{
je.printStackTrace();
}
}
}
But I am getting fol;owing error:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/2001/XMLSchema", local:"schema"). Expected elements are (none)
Can you please tell me whats wrong I am doing?
Any help is greatly appreciated.
I think you are missing a few steps. You didn't post what report.xsd is, nor a sample xml, so I'm going to take a few guesses.
For starters, you are trying to unmarshal the xsd and not xml, which is itself the root of the problem. That being said, your Report.java class does not look properly generated so it is unlikely that your unmarshalling would work even if you tried against your xml file.
If you have a properly created XSD file, the first thing you should do is create the JaxB POJOs using xjc. xjc comes installed with java, and you use it to create annotated java classes from the xsd. It will also create 2 additional files - ObjectFactory.java and package-info.java which are used by JAXB. (You can specify the output path using the -d param (see --help for the full list of switches)
xjc -d c:\dev\myproject\src\main\java report.xsd
Once you have those files generated, you have to create your JAXBContext based on that package/file.
JAXBContext jc = JAXBContext.newInstance(something.generated.Report.class);
Unmarshaller um = jc.createUnmarshaller();
Report myJAXBObject = (Report)um.unmarshal(new java.io.FileInputStream("report.xsd"), Report.class).getValue();
The unmarshaller generates a JAXBElement, from which you can extract the actual report class.
Hope this helps.
There are no properties on the bean you are trying to unmarshal. But more importantly, you are trying to deserialize your object from the XSD itself. The error message is a good indicator here:
unexpected element (uri:"http://www.w3.org/2001/XMLSchema", local:"schema")
JAXB is spitting out this error message because it is attempting to map the XSD's metadata to properties of your bean. Which of course, your bean doesn't actually have any. The next part of the error message indicates as much:
Expected elements are (none)
You need to define your Java Bean properly (put some properties on it!), and actually get an XML file that represents the serialized version of your bean.

Validating XML that is a DOM document

How do I validate an XML document that I already have in memory as a DOM Document?
You can use the javax.xml.validation APIs to validate XML in memory. Below is an example of using these APIs with a JAXBSource, to validate a DOM model simply use a DOMSource.
package blog.validation;
import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.util.JAXBSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
public class Demo {
public static void main(String[] args) throws Exception {
Customer customer = new Customer();
customer.setName("Jane Doe");
customer.getPhoneNumbers().add(new PhoneNumber());
customer.getPhoneNumbers().add(new PhoneNumber());
customer.getPhoneNumbers().add(new PhoneNumber());
JAXBContext jc = JAXBContext.newInstance(Customer.class);
JAXBSource source = new JAXBSource(jc, customer);
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("customer.xsd"));
Validator validator = schema.newValidator();
validator.setErrorHandler(new MyErrorHandler());
validator.validate(source);
}
}
For More Information
http://blog.bdoughan.com/2010/11/validate-jaxb-object-model-with-xml.html
How do you made up your model? I have a solution at work where i get an XML message in text format which i parse using xmlbeans. Then i have the ability to call a validate method on it. So there is a Java class compiled during my maven build which reflects the XSD i have.
There's nothing special about it. The javax.xml.validation validators take a Source. Check the constructors of the implementing classes of Source.

Categories

Resources