Marshalling with JaxbDataFormat in Apache Camel - jaxb

In all examples I see over the internet, need to call "setContext". but this function doesn't exist in JaxbDataFormat . Any idea or alternative way yo convert from xml to Json
// XML Data Format
JaxbDataFormat xmlDataFormat = new JaxbDataFormat();
JAXBContext con = JAXBContext.newInstance(Employee.class);
**xmlDataFormat.setContext(con);**
// JSON Data Format
JacksonDataFormat jsonDataFormat = new JacksonDataFormat(Employee.class);
from("file:C:/inputFolder").doTry().unmarshal(xmlDataFormat).
process(new MyProcessor()).marshal(jsonDataFormat).
to("jms:queue:javainuse").doCatch(Exception.class).process(new Processor() {
public void process(Exchange exchange) throws Exception {
Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
System.out.println(cause);
}
});
Thanks!

You can't find this function because either you aren't importing this package:
import org.apache.camel.converter.jaxb.JaxbDataFormat;
or because you aren't adding this dependency in your pom.xml:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jaxb</artifactId>
<version>${camel-version}</version>
</dependency>
You can check my reference archive here https://metiago.github.io/dev/2017/02/12/java-apache-camel-xml.html?query=camel for a better example.

Related

Premature end of file while marshaling xml

I am facing strange issue "Premature end of file." exception for last few days on one of our azure application. Its a spring boot application. I am using spring boot version 2.6.3 (embedded tomcat). This code has been working for past 8 months but its not working anymore. Only changes I did for Java 8 to Java 11 version update on the azure app service.
We are using "Java 11 on JAVA SE linux stack" in app service.
We are getting an exception on below line (setting new schema),
Schema schema = sf.newSchema(file);
Here is the Java code which was working before.
public static <T> String marshal(Class<T> beanClass, Object object, String xsdSchemaPath)
throws JAXBException, SAXException{
JAXBContext jaxbContext = JAXBContext.newInstance(beanClass);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
File file = new File(xsdSchemaPath);
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(xsdSchemaPath);
try {
FileUtils.copyInputStreamToFile(in, file);
} catch (IOException e) {
logger.error("Error occured in Marshalling the object", e.getMessage());
throw new SriException(xsdSchemaPath + " not found ");
}
Schema schema = sf.newSchema(file);
jaxbMarshaller.setSchema(schema);
I have already verified xsd and its valid.
Please let me know if there are any leads.
the only thing I can think about it's a max size issue or timeout. Take a look in the following and try changing the parameters:
In conf\server.xml
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxPostSize="67589953" />
In webapps\manager\WEB-INF\web.xml
<multipart-config>
<!-- 52MB max -->
<max-file-size>52428800</max-file-size>
<max-request-size>52428800</max-request-size>
<file-size-threshold>0</file-size-threshold>
</multipart-config>
HttpRequest maximum allowable size in tomcat?

create JSONObject and JSONArray in Liferay Portlet

Which is the best option to create a JSONObject and JSONArray in Liferay portlet?
You can't do Java simple way:
JSONObject json = new JSONObject();
JSONArray arrayJson = new JSONArray();
Error:
Cannot instantiate the type JSONObject
Cannot instantiate the type JSONArray
Tried with JSONFactoryUtil and it works but its deprecated.
com.liferay.util.json.JSONFactoryUtil
JSONObject json = JSONFactoryUtil.createJSONObject();
JSONArray arrayJson = JSONFactoryUtil.createJSONArray();
JSONFactoryUtil.createJSONObject() and JSONFactoryUtil.createJSONArray() are not deprecated, neither in Liferay 6.x nor in Liferay 7.x.
If you still want to use new JSONObject() and new JSONArray(), you can import org.json.
Maven:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
Gradle:
compileOnly group: 'org.json', name: 'json', version: '20190722'
Try a different version if this version doesn‘t work for you.

Spring Integrtion XML and Java Config Conversion

I am very new to Spring Integration and my project is using File Support to read a file and load into data base.
I have XML config , trying to understand it's content.
<int-file:inbound-channel-adapter auto-startup= true channel="channelOne" directory="${xx}" filename-regex="${xx}" id="id" prevent-duplicates="false">
<int:poller fixed-delay="1000" receive-timeout="5000"/>
</int-file:inbound-channel-adapter>
<int:channel id="channelOne"/>
From the above piece, my understanding is :
We define a channel and
Then define inbound-channel-adapter - this will look into directory for the file and create a message with file as a payload.
I was able to convert this in JavaConfig as below :
#Bean
public MessageChannel fileInputChannel() {
return new DirectChannel();
}
#Bean
#InboundChannelAdapter(value = "fileInputChannel", poller = #Poller(fixedDelay = "1000"))
public MessageSource<File> fileReadingMessageSource() {
FileReadingMessageSource sourceReader= new FileReadingMessageSource();
RegexPatternFileListFilter regexPatternFileListFilter = new RegexPatternFileListFilter(
file-regex);
//List<FileListFilter<File>> fileListFilter = new ArrayList<FileListFilter<File>>();
fileListFilter.add(regexPatternFileListFilter);
//CompositeFileListFilter compositeFileListFilter = new CompositeFileListFilter<File>(
fileListFilter);
sourceReader.setDirectory(new File(inputDirectorywhereFileComes));
sourceReader.setFilter(regexPatternFileListFilter );
return sourceReader;
}
Then the next piece of code , which literally I am struggling to understand and moreover to convert to JavaConfig.
Here is the next piece:
<int-file:outbound-gateway
delete-source-files="true"
directory="file:${pp}"
id="id"
reply-channel="channelTwo"
request-channel="channelOne"
temporary-file-suffix=".tmp"/>
<int:channel id="channelTwo"/>
<int:outbound-channel-adapter channel="channelTwo" id="id" method="load" ref="beanClass"/>
So from this piece , my understanding :
1: Define an output channel.
2: Define an outbound-gateway, which will write that message as a file again in directory(other one), also remove file from source directory. And finally it will call the method Load of Bean Class. This is our class and has load method which takes file as input and load it to DB.
I tried to covert it into Java Config. Here is my code:
#Bean
#ServiceActivator(inputChannel= "fileInputChannel")
public MessageHandler fileWritingMessageHandler() throws IOException, ParseException {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(path to output directory));
handler.setFileExistsMode(FileExistsMode.REPLACE);
beaObject.load(new File(path to output directory or input directory:: Nothing Worked));
handler.setDeleteSourceFiles(true);
handler.setOutputChannel(fileOutputChannel());
return handler;
}
I am able to write this file to output folder also was able to delete from source. After that I am totally lost. I have to call method Load of my BeanClass(ref=class in XML ).
I tried a lot, but not able to get it. Read multiple times the integration File Support doc, but couldn't make it.
Note: When I tried , I got one error saying , the File Not Found Exception. I believe , I am able to call my method , but can not get the file.
This XML config is working perfectly fine.
Spring Integration with DSL also anyone can suggest, if possible.
Please help me to understand the basic flow and get this thing done. Any help and comments is really appreciable.
Thanks in advance.
First of all you need to understand that #Bean method is exactly for configuration and components definitions which are going to be used later at runtime. You definitely must not call a business logic in the #Bean. I mean that your beaObject.load() is totally wrong.
So, please, go first to Spring Framework Docs to understand what is #Bean and its parent #Configuration: https://docs.spring.io/spring/docs/5.1.2.RELEASE/spring-framework-reference/core.html#beans-java
Your #ServiceActivator for the FileWritingMessageHandler is really correct (when you remove that beaObject.load()). What you just need is to declare one more #ServiceActivator for calling your beaObject.load() at runtime when message appears in the fileOutputChannel:
#ServiceActivator(inputChannel= "fileOutputChannel")
public void loadFileIntoDb(File payload) {
this.beaObject.load(payload);
}
See https://docs.spring.io/spring-integration/docs/5.1.1.BUILD-SNAPSHOT/reference/html/configuration.html#annotations for more info.

How to set Unmodifiable collection serializer of Kryo in Spark code

I am using Kryo serialization in Spark (v1.6.1) in Java and while serializing a class which has a collection in its field, it throws the following error -
Caused by: java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:102)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:18)
at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:648)
at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.read(FieldSerializer.java:605)
... 27 more
I found out that this is because the default CollectionSerializer of Kryo can not deserialize the collection, because its not modifiable and we should use UnmodifiableCollectionsSerializer instead.
How do I mention specifically in spark code to use UnmodifiableCollectionsSerializer for Kryo?
My current configuration is -
SparkConf conf = new SparkConf().setAppName("ABC");
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
conf.registerKryoClasses(new Class<?>[] {*list of classes I want to register*});
In case anybody else face this issue, here is the solution - I got it working by using javakaffee kryo serializers.
Add the following maven dependency:
<dependency>
<groupId>de.javakaffee</groupId>
<artifactId>kryo-serializers</artifactId>
<version>0.42</version>
</dependency>
Write a custom kryo registrator to register UnmodifiableCollectionsSerializer
public class CustomKryoRegistrator implements KryoRegistrator {
#Override
public void registerClasses(Kryo kryo) {
UnmodifiableCollectionsSerializer.registerSerializers(kryo);
}
}
Set spark.kryo.registrator to the custom registrator's fully-qualified name
conf.set("spark.kryo.registrator", "com.abc.CustomKryoRegistrator");
References -
https://github.com/magro/kryo-serializers
Spark Kryo: Register a custom serializer

Mockito with newInstance method

I have a class-under-test that has the following code :
public void getDetails (String message){
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
StringReader strReader = new StringReader(message);
InputSource inputSrc = new InputSource(strReader);
Document doc = docBuilder.parse(inputSrc);
...
}
I want to write a JUnit for this piece of code using Mockito.
I tried various things like :
DocumentBuilderFactory docBuilderFactoryMock = Mockito.mock(DocumentBuilderFactory.class);
Mockito.when(DocumentBuilderFactory.newInstance()).thenReturn(docBuilderFactoryMock);
But I get the Exception:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
DocumentBuilderFactory$$EnhancerByMockitoWithCGLIB$$23223735 cannot be returned by toString()
toString() should return String
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
If I do the following:
DocumentBuilderFactory docBuilderFactoryMock = Mockito.spy(DocumentBuilderFactory.newInstance());
DocumentBuilder documentBuilderMock = Mockito.mock(DocumentBuilder.class);
Mockito.when(docBuilderFactory.newDocumentBuilder()).thenReturn(documentBuilderMock);
docBuilderdocBuilderMockito.when(docBuilderFactoryMock.newDocumentBuilder()).thenReturn(docBuilderFactoryMock);
and debug my code then I see that the class-under-test does not use my Mock objects anywhere but creates its own objects and throws a SAXParseException at
Document doc = docBuilder.parse(inputSrc);
Unit testing is intended to test your components/classes, not the library components/classes that are used.
Your class is parsing a String as xml content and to test that, you will find that providing a set of xml Strings with known output is the best way to test.
Simply pass a known xml String to your class under test and assert that the resulting model that is parsed, contains the data that you expect for that xml content.
I don't think that you need any mocking.

Resources