remove null value field from apache cxf REST response - apache

I'm using apache-cxf 2.7.11 + jackson (codehaus) 1.9.13 + spring 3.5 in my REST services web-container. I was wondering what would be the best way to remove null value fields from REST responses.
For example:
My response is now like this:
{
"name": "MyName",
"age": 10,
"address": null
}
I want my response to be like this (the address field has been removed):
{
"name": "MyName",
"age": 10
}
I've read about apache-cxf interceptors and filters here:
http://cxf.apache.org/docs/jax-rs-filters.html
http://cxf.apache.org/docs/jax-rs-data-bindings.html
and wondering what is the best practice? is there any configurable setting that I can change instead of implementing my own filer or interceptor class?
I'm using beans.xml file for configuration, thus I'm looking on how to config it all here, where my beans are:
<bean id="jaxrsRestJacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider">
<property name="mapper" ref="jaxrsRestJacksonObjectMapper"/>
</bean>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
Cheers!

Found it!
This is the answer I was looking for:
see the updated beans.xml file:
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper">
<property name="serializationInclusion" value="NON_NULL"/>
</bean>
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider">
<property name="mapper" ref="jacksonObjectMapper"/>
</bean>

You could add
#JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
on top of your POJO class. This would ignore the null fields for that one class.
Or you could configure the ObjectMapper so it would apply globally
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
If you go with the latter, you can pass the ObjectMapper as a constructor arg to the JacksonJsonProvider or JacksonJaxbJsonProvider (whichever one you are currently using)
UPDATE
You could also use a ContextResolver as seen here, and register the ContextResolver like you would any other provider. This will work better more complicated configurations. You might want to do that instead. With the ContextResolver, you don't need to configure the ObjectMapper with the JacksonJsonProvider, but you still do need the JacksonJsonProvider.

Related

saslConfig using spring rabbitmq not working

My project needed SSL authentication mechanism to be EXTERNAL(using SSL certificates only and avoiding username/password on rabbitmq). For the connectionfactory bean we gave property name="saslConfig" value= "DefaultSaslConfig.EXTERNAL", but we are getting an error: "Cannot convert value of type [java.lang.String] to required type [com.rabbitmq.client.SaslConfig] for property 'saslConfig': no matching editors or conversion strategy found". we tried other values like value= "com.rabbitmq.client.DefaultSaslConfig.EXTERNAL" and value="EXTERNAL", but still the error persists. Can you please check on the configuration and logs below and provide me your suggestions.
Bean configuration
<rabbit:connection-factory id="connectionFactory" connection-factory="clientConnectionFactory" host="x.y.z.m" port="5671"/>
<bean id="clientConnectionFactory" class="org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean">
<property name="useSSL" value="true" />
<property name="saslConfig" value=com.rabbitmq.client.DefaultSaslConfig.EXTERNAL"/>
<property name="sslPropertiesLocation" value="classpath:/rabbitSSL.properties"/></bean>
Logs
Caused by: java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.rabbitmq.client.SaslConfig] for property 'saslConfig': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:306)
at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:576)
The following worked for me (source: https://github.com/spring-projects/spring-boot/issues/6719#issuecomment-259268574):
#PostConstruct
public void init() {
if (rabbitProperties.getSsl().isEnabled() && rabbitProperties.getSsl().getKeyStore() != null) {
cachingConnectionFactory.getRabbitConnectionFactory().setSaslConfig(DefaultSaslConfig.EXTERNAL);
}
}
EXTERNAL is a static variable, not an enum.
Use
"#{T(com.rabbitmq.client.DefaultSaslConfig).EXTERNAL}"
which is a SpEL expression using the type operator (T) to get a reference to the static.
See SpEL
We can use ConnectionFactoryCustomizer in package org.springframework.boot.autoconfigure.amqp
to set sasl config on rabbitmq connection factory on bean creation.
#Autowired
RabbitProperties rabbitProperties
#Bean
ConnectionFactoryCustomizer connectionFactoryCustomizer() {
if (rabbitProperties.getSsl().getEnabled() && rabbitProperties.getSsl().getKeyStore() != null) {
return (connectionFactory) -> connectionFactory.setSaslConfig(DefaultSaslConfig.EXTERNAL)
}
return (connectionFactory) -> connectionFactory.setSaslConfig(DefaultSaslConfig.PLAIN)
}

start working with jpos

I am creating a new payment application. What I have is a client application that user selects price, enter its authentication information and then client creates and iso 8583 message and send this data to a bank server.
According to my researches, I can use jPOS for emulating bank server. Actually I need a server for getting the iso messages and response to them but I do not know how can I use jPOS for this propose.
I searched for this in the internet but could not find any resource that answer we clearly. My main question is that whether I need to create an application using jPOS for implementing my requirements or only installing the jPOS on the server is enough for testing my client app?
Well, read jpos library documentation its draft version is available on the web you can find it here
Specific to your question about JPOS Server better to implement your own server. JPos provides class ISOServer e.g. following beans initiates a ISO Server in applicationContext.xml file
<bean id="paymentServer" class="org.jpos.iso.ISOServer">
<constructor-arg>
<value>13000</value>
</constructor-arg>
<constructor-arg ref="paymentChannel" />
<constructor-arg ref="paymentServerThreadPool" />
</bean>
<bean id="paymentChannel" class="org.jpos.iso.channel.ASCIIChannel">
<constructor-arg ref="paymentPackager" />
</bean>
<bean id="paymentPackager" class="com.sample.payment.packager.PaymentPackager"/>
<bean id="paymentServerThreadPool" class="org.jpos.util.ThreadPool">
<constructor-arg>
<value>1</value>
</constructor-arg>
<constructor-arg>
<value>100</value>
</constructor-arg>
<constructor-arg>
<value>PaymentServer</value>
</constructor-arg>
</bean>
<bean id="paymentProcessor" class="com.sample.processors.PaymentProcessor" init-method="init"/>
Following class to implement packager
public class PaymentPackager extends ISOBasePackager {
protected ISOFieldPackager fld[] = {
/* 0000 */ new IFB_NUMERIC ( 4, "Message Type Indicator", false),
/* 0001 */ new IFB_BITMAP ( 16, "Bitmap"),
/* 0002 */ new IFB_LLLCHAR (999, "Primary Account number"),
/* 0003 */ new IFB_NUMERIC ( 6, "Processing Code", true),
/* 0004 */ new IFB_NUMERIC ( 12, "Amount, Transaction", true),
//.....
/* 0063 */ new IFB_LLLCHAR (999, "Reserved for national use"),
/* 0064 */ new IFB_BINARY ( 20, "Message authentication code field"),
//.....
/* 0125 */ new IF_UNUSED (),
/* 0126 */ new IF_UNUSED (),
/* 0127 */ new IF_UNUSED (),
/* 0128 */ new IFB_BINARY ( 20, "Message authentication code field"),
};
public PaymentPackager() {
super();
setFieldPackager(fld);
}
}
In application entry point class you can get the bean and use like following to attach the channel listener
paymentServer.addISORequestListener(paymentProcessor);
following is the sample listener
public class PaymentProcessor implements ISORequestListener {
private static Logger log = LoggerFactory.getLogger(PaymentProcessor.class);
public void init() {
//do init
}
public boolean process (ISOSource source, ISOMsg m){
log.debug(">PaymentProcessor.process");
ISOMsg request = (ISOMsg) m.clone();
ISOMsg response = new ISOMsg();
//...
//build your response
//...
source.send(response);
return true;
}
}
NOTE: I have not implemented it yet but jpos provides new way to implement server and client using Q2 you can see documentation of QServer class to implement server, I'll try to share sample as soon as I could.
Happy coding :)

Set datasource for custom itemWriter (spring batch)

I want to read from a database and write to another database using a custom itemWriter.
How can I set datasource for custom itemWriter?
Please have a look at this sample project Spring Batch Example
Here is sample code for your custom ItemWriter.
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.stereotype.Component;
import com.x.y.z.MyBean;
#Component("myJdbcWriter")
public class MyCustomJdbcWriter extends JdbcBatchItemWriter<MyBean> {
MyCustomJdbcWriter() {
}
#Override
#Resource
public void setDataSource(DataSource dataSource) {
super.setDataSource(dataSource);
}
// define other methods also that you want to override in the same manner
}
Either use auto-detect feature of Spring or you can define a bean in your spring xml configuration file as shown below and use this bean in you respective job.
<bean id="myJdbcWriter" class="com.x.y.z.MyCustomJdbcWriter"
scope="step">
<property name="dataSource" ref="dataSource" />
</bean>

How to set a spring.NET AOP advice before method call

I want to intercept a method call before execution using spring.NET. Let's assume the class/method to be intercepted is:
public class Listener
{
public void Handle()
{
// method body
}
}
This is what I've done (assuming all code is in a namespace called Example):
1.Created the advice:
public class MyAopAdvice : IMethodBeforeAdvice
{
public void Before(MethodInfo method, object[] args, object target)
{
// Advice action
}
}
2.Updated my spring xml configs:
<object id="myAopAdvice" type="Example.MyAopAdvice" />
<object id="listener" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Example.Listener" autowire="autodetect"/>
</property>
<property name="InterceptorNames">
<list>
<value>myAopAdvice</value>
</list>
</property>
</object>
For some reason my Advice code is not getting hit if I put a breakpoint in it. However, if I add some console logging statements within my advice, it seems they are logged, but not at the appropriate time (i.e., before calling Listener.Handle()).
I'm willing to bet my configs are wrong (for once, I may be missing a way to tell the configs to listen for just the Handle method call and not any other method that Listener may have). Any ideas what's wrong?
Declare your Handle method as virtual:
public virtual void Handle() // ...
Your class does not implement any interfaces, which spring.net's default aop mechanism uses to create proxies. When spring.net does not find any interfaces to proxy, it looks for virtual methods to create a proxy for a class.

Apache - CXF jaxrs-server - unable to hit the resource which is defined first in jaxrs-server endpoint

I'm using Apache-CXF for JAX-RS implementation. I have two resources which are defined in two bean. My jaxrs-server in context.xml os as follow
<jaxrs:server id="serverId" address="/">
<jaxrs:serviceBeans>
<bean id="bean1" class="com.Bean1" />
<bean id="bean2" class="com.Bean2" />
</jaxrs:serviceBeans>
</jaxrs:server>
Interface for Bean1 is as follows -
#Path("/")
public interface IBean1 {
#GET
#Path("/beaninfo1")
#Produces({ MediaType.APPLICATION_XML })
public Response checkBean1();
}
Interface for Bean2 is as follows -
#Path("/")
public interface IBean2 {
#GET
#Path("/beaninfo2")
#Produces({ MediaType.APPLICATION_XML })
public Response checkBean1();
}
I'm unable to hit the resource which is defined in last in serviceBans definition. In this case i'm able to hit Bean2 but not Bean1, getting 404 error, where as if i put Bean2 first and then Bean1, i'm able to hit Bean1 only.
Is there anything wrong with my configuration ?
It is possible to have the same #Path annotation at class level. You need to use a resourcecomparator. Please check this question
Yes. Give them different #Path annotations at the class level.