How to force a JAXBException when marshalling for a JUnit test - jaxb

I haven't been able to find a way to force a JAXBException when marshalling for a JUnit test. Does anyone have any ideas?
Here is my marshalling code:
public String toXml() {
log.debug("Entered toXml method");
String result = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
jaxbMarshaller.marshal(this, writer);
result = writer.toString();
} catch (JAXBException e) {
log.error(e);
}
log.debug("Exiting toXml method");
return result;
}

There are different ways to create a JAXBException during a marshal operation:
1 - Marshal an Invalid Object
You can generate a JAXBException during a marshal operation by marshalling an instance of a class that the JAXBContext isn't aware of (i.e. Take your example and use it to marshal an instance of Foo). This will produce the following exception.
Exception in thread "main" javax.xml.bind.JAXBException: class forum13389277.Foo nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:482)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at forum13272288.Demo.main(Demo.java:27)
2 - Marshal to Invalid Output
If you try to marshal to an invalid output such as an OutputStream that has been closed:
FileOutputStream closedStream = new FileOutputStream("src/foo.xml");
closedStream.close();
jaxbMarshaller.marshal(this, closedStream);
Then you will get a MarshalException which is a subclass of JAXBException.
Exception in thread "main" javax.xml.bind.MarshalException
- with linked exception:
[java.io.IOException: Stream Closed]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:320)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at forum13272288.Demo.main(Demo.java:27)
Caused by: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:318)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.flushBuffer(UTF8XmlOutput.java:413)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.endDocument(UTF8XmlOutput.java:137)
at com.sun.xml.bind.v2.runtime.output.IndentingUTF8XmlOutput.endDocument(IndentingUTF8XmlOutput.java:165)
at com.sun.xml.bind.v2.runtime.XMLSerializer.endDocument(XMLSerializer.java:852)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.postwrite(MarshallerImpl.java:369)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:316)
... 3 more

Related

No conversion value provided for the attribute [CO]

I have an xsd which conatins a entity Taddress having a property country_code which has enum type. I am uanble to marshal the xml out of the root entity because it throws an exception as below
javax.xml.bind.MarshalException
- with linked exception: [Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.XMLMarshalException Exception
Description: An error occurred marshalling the object Internal
Exception: Exception [EclipseLink-115] (Eclipse Persistence Services -
2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException Exception
Description: No conversion value provided for the attribute [CO].
Mapping:
org.eclipse.persistence.oxm.mappings.XMLDirectMapping[countryCode-->country_code/text()]
Descriptor: XMLDescriptor(generated.TAddress --> [])] at
org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:403)
at
com.crrinfra.dynamicOutputgen.utils.HelloWorld.generateTransaction(HelloWorld.java:52)
at
com.crrinfra.dynamicOutputgen.utils.XMLUtilities.generateJaxBContext(XMLUtilities.java:259)
at
com.crrinfra.dynamicOutputgen.utils.DynamicXSDLoader.populateCache(DynamicXSDLoader.java:48)
at
com..crrinfra.dynamicOutputgen.DynamicOutputXSDParser.main(DynamicOutputXSDParser.java:16)
Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services
- 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException Exception
Description: An error occurred marshalling the object Internal
Exception: Exception [EclipseLink-115] (Eclipse Persistence Services -
2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException Exception
Description: No conversion value provided for the attribute [CO].
Mapping:
org.eclipse.persistence.oxm.mappings.XMLDirectMapping[countryCode-->country_code/text()]
Descriptor: XMLDescriptor(generated.TAddress --> []) at
org.eclipse.persistence.exceptions.XMLMarshalException.marshalException(XMLMarshalException.java:97)
at
org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:911)
at
org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:848)
at
org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:401)
... 4 more
public class HelloWorld {
public static void generateTransaction(DynamicJAXBContext jaxbContext) throws JAXBException, NoSuchFieldException, SecurityException{
DynamicEntity entity = jaxbContext.newDynamicEntity("generated.Report");
DynamicType type = jaxbContext.getDynamicType("generated.Report");
DynamicEntity childEntity3 = jaxbContext.newDynamicEntity("generated.TAddress");
DynamicType type1 = jaxbContext.getDynamicType("generated.TAddress");
childEntity3.set("addressType", "M");
childEntity3.set("address", "XXXX");
childEntity3.set("town", "XXX");
childEntity3.set("city", "XXXXX");
childEntity3.set("zip", "751006");
childEntity3.set("countryCode", "CO");
childEntity3.set("state", "OD");
childEntity3.set("comments", "Permanent Address");
entity.set("location", childEntity3);
XMLDirectMapping enumMappings = (XMLDirectMapping) ((DynamicTypeImpl) type1).getMapping("countryCode");
System.out.println(enumMappings.isDirectToFieldMapping());
JAXBMarshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(entity, System.out);
}
}
Please advise on how to set the property. I have uploaded the xsd with this question
I have found the answer to my question and hence thought of closing this thread. I would be happy to receive feedback on this approach
public class EnumAttributeHandler implements IAttributeHandler {
DynamicTypeImpl typeAttr;
public EnumAttributeHandler(DynamicTypeImpl typeAttr) {
// TODO Auto-generated constructor stub
this.typeAttr=typeAttr;
}
#Override
public DynamicEntity attributeSetter(CRROutputAttributePojo attrPojo, DynamicEntity currentEntitytag, HashMap<String, Object> params,String setterValue) throws CRROutputGenException {
// TODO Auto-generated method stub
XMLDirectMapping enumMappings = (XMLDirectMapping) (typeAttr)
.getMapping(attrPojo.getActualAttrName());
EnumTypeConverter converter=null;
if(enumMappings.getConverter() instanceof EnumTypeConverter)
converter = (EnumTypeConverter) enumMappings.getConverter();
else
throw new CRROutputGenException("Invalid type of converter");
try {
if (setterValue != null) {
Object enumField = ((DynamicJAXBContext) params.get("jaxbContext")).getEnumConstant(converter.getEnumClassName().toString(), setterValue);
currentEntitytag.set(attrPojo.getActualAttrName(), enumField);
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new CRROutputGenException(e.getMessage());
}
return currentEntitytag;
}
}

Trying to integrate Spring Batch with spring integration getting error

The below class is used to poll for a file in a directory and trigger the spring batch once a file is received in a directory. I am getting some error, which I am not able to figure out. please advice.
Also, if there is some sample code example to do the same, please refer me to that location.
#Configuration
class FilePollingIntegrationFlow {
#Autowired
private ApplicationContext applicationContext;
// this is the integration flow that foirst polls for messages and then trigger the spring batch job
#Bean
public IntegrationFlow inboundFileIntegration(#Value("${inbound.file.poller.fixed.delay}") long period,
#Value("${inbound.file.poller.max.messages.per.poll}") int maxMessagesPerPoll,
TaskExecutor taskExecutor,
MessageSource<File> fileReadingMessageSource,
JobLaunchingGateway jobLaunchingGateway) {
return IntegrationFlows.from(fileReadingMessageSource,
c -> c.poller(Pollers.fixedDelay(period)
.taskExecutor(taskExecutor)
.maxMessagesPerPoll(maxMessagesPerPoll)))
.transform(Transformers.fileToString())
.channel(ApplicationConfiguration.INBOUND_CHANNEL)
.handle((p, h) -> {
System.out.println("Testing:::::"+p);
return p;
})
.handle(fileMessageToJobRequest())
.handle(jobLaunchingGateway(),"toRequest")
.channel(MessageChannels.queue())
.get();
}
#Bean
public FileMessageToJobRequest fileMessageToJobRequest() {
FileMessageToJobRequest fileMessageToJobRequest = new FileMessageToJobRequest();
fileMessageToJobRequest.setFileParameterName("input.file.name");
// fileMessageToJobRequest.setJob(personJob());
System.out.println("FilePollingIntegrationFlow::fileMessageToJobRequest::::Job launched successfully!!!");
return fileMessageToJobRequest;
}
#Bean
public JobLaunchingGateway jobLaunchingGateway() {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
// simpleJobLauncher.setJobRepository(jobRepository);
simpleJobLauncher.setTaskExecutor(new SyncTaskExecutor());
JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(simpleJobLauncher);
System.out.println("FilePollingIntegrationFlow::jobLaunchingGateway::::Job launched successfully!!!");
return jobLaunchingGateway;
}
//This is another class used for batch job trigger
public class FileMessageToJobRequest {
private Job job;
private String fileParameterName;
public void setFileParameterName(String fileParameterName) {
this.fileParameterName = fileParameterName;
}
public void setJob(Job job) {
this.job = job;
}
#Transformer
public JobLaunchRequest toRequest(Message<File> message) {
JobParametersBuilder jobParametersBuilder =
new JobParametersBuilder();
jobParametersBuilder.addString(fileParameterName,
message.getPayload().getAbsolutePath());
return new JobLaunchRequest(job, jobParametersBuilder.toJobParameters());
}
}
I am getting the below error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'inboundFileIntegration' defined in class path resource [com/porterhead/integration/file/FilePollingIntegrationFlow.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFileIntegration' threw exception; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
at com.porterhead.Application.main(Application.java:23)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFileIntegration' threw exception; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 16 common frames omitted
Caused by: java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:494)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:226)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:135)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:139)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.<init>(MethodInvokingMessageProcessor.java:52)
at org.springframework.integration.handler.ServiceActivatingHandler.<init>(ServiceActivatingHandler.java:45)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:982)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:964)
at com.porterhead.integration.file.FilePollingIntegrationFlow.inboundFileIntegration(FilePollingIntegrationFlow.java:85)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9.CGLIB$inboundFileIntegration$1(<generated>)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9$$FastClassBySpringCGLIB$$4ce6110e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9.inboundFileIntegration(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 17 common frames omitted
Please advice.
Since your FileMessageToJobRequest.toRequest() is marked with the #Transformer you should consider to use .transform() instead.
Also I see that you use that toRequest method name for the JobLaunchingGateway what is definitely wrong. So, the proper way to go is like this:
.transform(fileMessageToJobRequest())
.handle(jobLaunchingGateway())
The sample you are looking for is in the Spring Batch Reference Manual.

Unmarshalling the XML using JAXB

Actually I am very new at spring and currently due to some requirement, I am working with spring-integration, I have made few JAXB classes to convert the data into XML and have to send it through webservices but in response I am getting the XML back with some new element, I want to know how to unmarshall the new XML with same JAXB classes that I have made?
I use the following component to do that (java configuration):
#Bean
public Jaxb2Marshaller jaxb2Marshaller() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
/* Packages with root elements (#XmlRootElement). Your JAXB classes */
marshaller.setContextPaths("...");
return marshaller;
}
#Bean
#ServiceActivator(inputChannel = "toWebServiceChannel")
public MessageHandler wsGateway() throws Exception {
ConfigWebServiceURLProvider provider = new ConfigWebServiceURLProvider(isHttps, host, port, endpoint);
/* marshaller and unmarshaller could be the same */
MarshallingWebServiceOutboundGateway gw = new MarshallingWebServiceOutboundGateway(url, jaxb2Marshaller(), jaxb2Marshaller());
gw.setOutputChannelName( "fromWebServiceChannel" );
return gw;
}

org.apache.camel.InvalidPayloadException: No body available of type error thrown while unMarshalling Jaxb Object

I am sending JAXB Object to Rabbit MQ via Java.
JAXBContext jaxbContext = JAXBContext.newInstance(MyDTO.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
java.io.StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(deliveryrequest, sw);
ConnectionFactory factory = new ConnectionFactory() ;
//TODO change the hardcoding to the properties file
factory.setHost("rabbitmq.host.net");
factory.setUsername("user");
factory.setPassword("pass");
Channel channel ;
Connection connection;
Map<String, Object> args = new HashMap<String, Object>();
String haPolicyValue = "all";
args.put("x-ha-policy", haPolicyValue);
connection = factory.newConnection();
channel = connection.createChannel();
//TODO change the hardcoding to the properties file
channel.queueDeclare("upload.com.some.queue", true, false, false, args);
//TODO change the hardcoding to the properties file
channel.basicPublish("com.some.exchange", "someroutingKey",
new AMQP.BasicProperties.Builder().contentType("text/plain")
.deliveryMode(2).priority(1).userId("guest").build(),
sw.toString().getBytes());
I am using Camel in different application to read this.
<camel:route id="myRoute">
<camel:from uri="RabbitMQEndpoint" />
<camel:to uri="bean:MyHandler" />
</camel:route>
Handler is using the Jaxb object redone in camel side
#Handler
public void handleRequest(MyDTO dto) throws ParseException {
I am getting the error which I did not expect to get.
Caused by: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: byte[] to the required type: com.mycompany.MyDTO with value [B#1b8d3e42
at org.apache.camel.impl.converter.BaseTypeConverterRegistry.mandatoryConvertTo(BaseTypeConverterRegistry.java:181)
at org.apache.camel.impl.MessageSupport.getMandatoryBody(MessageSupport.java:99)
Solution is appreciated.
Your message body type from rabbit is a byte[], and you want to call a bean which as MyDTO type. You have a type mismatch. And Camel cannot find a type converter that can convert the message body from byte[] to your MyDTO type.
Is the byte[] data from Rabbit in XML format? And do you have JAXB annotations on MyDTO classes, so you could use JAXB to marshal that from xml to Java ?
It is Jaxb object. I was under impression that if i move the publisher too Camel. Things will be sorted out.
I changed the publisher to the following.
#EndpointInject(context = "myContext" , uri = "direct:myRoute")
private ProducerTemplate sendAMyContext;
And in method I called
#Override
public MyResponse putMyCall(
MyRequest myrequest) {
sendMyContext.sendBody(myrequest);
My camel route is simple one
<camel:camelContext id="MyContext" autoStartup="true" xmlns="http://camel.apache.org/schema/spring">
<camel:endpoint id="myQueue" uri="${my.queue.1}" />
<camel:route>
<camel:from uri="direct:myRoute"/>
<camel:to uri="bean:mySendHandler"/>
<camel:convertBodyTo type="String"></camel:convertBodyTo>
<camel:to uri="ref:myQueue" />
</camel:route>
</camel:camelContext>
I added the handler to convert the Jaxb object to string(because of error)
public class MySendHandler {
#Handler
public String myDelivery( MyRequest myRequest) throws ParseException, JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(MyRequest.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
java.io.StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(attributedDeliveryRequest, sw);
return sw.toString();
}
Still the same error
[SpringAMQPConsumer.SpringAMQPExecutor-1] WARN org.springframework.amqp.support.converter.JsonMessageConverter (JsonMessageConverter.java:111) - Could not convert incoming message with content-type [text/plain]
SpringAMQPConsumer.SpringAMQPExecutor-1] ERROR org.apache.camel.processor.DefaultErrorHandler (MarkerIgnoringBase.java:161) - Failed delivery for (MessageId: ID-Con ExchangeId: ID-65455-1380873539452-3-2).
Exhausted after delivery attempt: 1 caught: org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[Message: <XML>]
org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[Message: <xml>
.....
Caused by: org.apache.camel.InvalidPayloadException: No body available of type: MyDTO but has value: [B#7da255c of type: byte[] on: Message: <xml>
. Caused by: [org.apache.camel.NoTypeConversionAvailableException - No type converter available to convert from type: byte[] to the required type: MyDeliveryDTO with value [B#7da255c]
at org.apache.camel.impl.MessageSupport.getMandatoryBody(MessageSupport.java:101)
at org.apache.camel.builder.ExpressionBuilder$38.evaluate(ExpressionBuilder.java:934)
... 74 more
Caused by: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: byte[] to the required type: MyDTO with value [B#7da255c
at org.apache.camel.impl.converter.BaseTypeConverterRegistry.mandatoryConvertTo(BaseTypeConverterRegistry.java:181)
at org.apache.camel.impl.MessageSupport.getMandatoryBody(MessageSupport.java:99)
... 75 more
My receiving camel route is as below
<camel:route id="processVDelivery">
<camel:from uri="aVEndpoint" />
<camel:to uri="bean:myDataHandler" />
</camel:route>
I added
<camel:convertBodyTo type="String"></camel:convertBodyTo>
to it and it gave me error that it cannot convert it from string to the object
adding this
<camel:unmarshal></camel:unmarshal>
-------------------------
Answer to the question will be all your mashaller have to be part of classpath
---------------------------------
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>${jackson.version}</version>
</dependency>
------- Also you can the custom marshaller using dataformat
<camel:dataFormats>
<camel:jaxb id="name" contextPath="com.something"/>
</camel:dataFormats
make sure that you keep jaxb.index file in com.something package with the root level Jaxb object name
Using Camel Rest with Spring boot
rest("/authenticate")
.post()
.route()
.setHeader("Content-Type", constant("application/json"))
.setHeader("Accept", constant("application/json"))
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.process(exchange -> {
org.apache.camel.TypeConverter tc = exchange.getContext().getTypeConverter();
String str_value = tc.convertTo(String.class, exchange.getIn().getBody());
System.err.println(str_value);
exchange.getOut().setBody(str_value);
})
//.removeHeader(Exchange.HTTP_URI)
.to("http://localhost:8082/authenticate?bridgeEndpoint=true")
//.convertBodyTo(DTO.class)
.log("Boo!")
.end()
.endRest();

How can I unlock a file locked by JAXB's unmarhsaller

I'm unmarshalling an XML file with JAXB w/Java 1.7.0_03 on Windows 7 x64 using the following code:
try (InputStream xsdStream = ConfigurationService.class.getClassLoader().getResourceAsStream(CONFIG_XSD_FILE_NAME)) {
configFile = new File(configFilePath);
if (configFile.exists()) {
context = JAXBContext.newInstance(Config.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
StreamSource xsdStreamSource = new StreamSource(xsdStream);
Schema schema = sf.newSchema(xsdStreamSource);
unMarshaller.setSchema(schema);
Object xmlObject = Config.class.cast(unMarshaller.unmarshal(configFile));
myConfig = (Config) xmlObject;
} else {
log.severe(configFile.getAbsolutePath() + " does not exist, can not parse configuration info from it.");
}
}
Code which calls this method subsequently deletes the XML file.
The XML file will properly delete if unmarhalling is successful. However, if the above code throws and Exception, eg. a SAXException, the XML file remains locked indefinitely and the calling code is not able to delete it with File.delete().
This feels like JAXB is not closing the resource/file in this case. Is it my responsibility to do that somehow or is this a bug?
Reviewing the javadoc for Unmarshaller did not shed any light on this and Googling this issue revealed this old, unanswered question from 2008.
SHORT ANSWER
The behaviour you have described sounds like a bug in the JAXB reference implementation. You can open a ticket using the link below:
http://java.net/jira/browse/JAXB/
Work Around
Instead of unmarshalling from a File you can unmarshal from a FileInputStream and control that it is closed correctly yourself after unmarshalling.
LONG ANSWER
I have not been able to reproduce the issue that you are seeing. I have included what I have tried below. I am using JDK 1.7.0_07 x64 for the Mac.
Configuration Service
Most of the code below is copied from your question. I have added the call to delete the input file and then output if the file still exists.
package forum14765898;
import java.io.*;
import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
public class ConfigurationService {
private static final String CONFIG_XSD_FILE_NAME = "forum14765898/schema.xsd";
public static void main(String[] args) throws Exception {
File configFile = null;
String configFilePath = "src/forum14765898/input.xml";
JAXBContext context;
Config myConfig;
try (InputStream xsdStream = ConfigurationService.class.getClassLoader().getResourceAsStream(CONFIG_XSD_FILE_NAME)) {
configFile = new File(configFilePath);
if (configFile.exists()) {
context = JAXBContext.newInstance(Config.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
StreamSource xsdStreamSource = new StreamSource(xsdStream);
Schema schema = sf.newSchema(xsdStreamSource);
unMarshaller.setSchema(schema);
Object xmlObject = Config.class.cast(unMarshaller.unmarshal(configFile));
myConfig = (Config) xmlObject;
} else {
//log.severe(configFile.getAbsolutePath() + " does not exist, can not parse configuration info from it.");
}
} catch(Exception e) {
e.printStackTrace(System.out);
}
configFile.delete();
System.out.println(configFile.exists());
}
}
schema.xsd
Below is the simple XML schema that I am using.
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="config">
<complexType>
<sequence>
<element name="bar" type="int"/>
</sequence>
</complexType>
</element>
</schema>
input.xml
Below is the XML input. The bar element is not valid according to the XML schema. When a Schema is set on the Unmarshaller this document will be enough to cause an Exception to be thrown while performing an unmarshal operation.
<?xml version="1.0" encoding="UTF-8"?>
<config>
<bar>INVALID</bar>
</config>
Config
package forum14765898;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Config {
public int bar;
}
Output
Below is output from running the demo code. It shows both the validation exception and on the last line we see that the XML file was successfully deleted as it no longer exists.
javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; systemId: file:/Users/bdoughan/Scratch/src/forum14765898/input.xml; lineNumber: 3; columnNumber: 23; cvc-datatype-valid.1.2.1: 'INVALID' is not a valid value for 'integer'.]
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:512)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:209)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:175)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:189)
at forum14765898.ConfigurationService.main(ConfigurationService.java:31)
Caused by: org.xml.sax.SAXParseException; systemId: file:/Users/bdoughan/Scratch/src/forum14765898/input.xml; lineNumber: 3; columnNumber: 23; cvc-datatype-valid.1.2.1: 'INVALID' is not a valid value for 'integer'.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:325)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:453)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3232)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(XMLSchemaValidator.java:3147)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(XMLSchemaValidator.java:3057)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(XMLSchemaValidator.java:2135)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(XMLSchemaValidator.java:854)
at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(ValidatorHandlerImpl.java:579)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.endElement(ValidatingUnmarshaller.java:91)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(SAXConnector.java:143)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1742)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2900)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:116)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:489)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203)
... 6 more
false
public CashCountCompleted CashDeposit(String path) throws Exception {
// TODO Auto-generated method stub
CashCountCompleted cashCountCompleted = null;
File file = null;
FileInputStream inputStram = null;
try {
file = new File(path);
inputStram = new FileInputStream(file);
JAXBContext jaxbContext = JAXBContext.newInstance(CashCountCompleted.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
cashCountCompleted = (CashCountCompleted) jaxbUnmarshaller.unmarshal(inputStram);
}catch (JAXBException e) {
//throw new...
} catch (FileNotFoundException e) {
//throw new...
}finally{
try{
if(inputStram !=null){
inputStram.close();
}
}catch(Exception exception){
//throw new...
}
}
return cashCountCompleted;
}

Resources