What is the proper replacement of the Resteasy 2.X ClientErrorInterceptor? - exception

We are working on the migration from resteasy 2.x to 3.x and are not happy about the use of the deprecated org.jboss.resteasy.client.ClientResponse within org.jboss.resteasy.client.core.ClientErrorInterceptor#handle - method.
Thus we are searching for proper replacement with which we are able to rethrow all service exception at a single place within the service client library, even if ClientResponse is replaced in new versions of resteasy.
The existing solution with resteasy 2.x looks like:
public class ServiceClientErrorInterceptor implements ClientErrorInterceptor
{
#Override
public void handle(ClientResponse<?> response)
{
throw response.getEntity(ServiceExceptionObject.class).getException();
}
}

Related

Spring-boot Redis JMS JUnit

I am using Redis Server for message broker in my spring boot application.
Is there any simple way to Junit my publish and receive API?
e.g :
Publisher :
public String publish(Object domainObj) {
template.convertAndSend(topic.getTopic(), domainObj.toString());
return "Event Published";
}
Receiver :
public class Receiver implements MessageListener {
#Override
public void onMessage(Message message, byte[] bytes) {
System.out.println("Consumed Message {}" + message);
}
}
I am using JedisConnectionFactory and RedisMessageListenerContainer and RedisTemplate for my implementation
#Configuration
#EnableRedisRepositories
public class RedisConfig {
#Bean
public JedisConnectionFactory connectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName("localhost");
configuration.setPort(6379);
return new JedisConnectionFactory(configuration);
}
#Bean
public RedisTemplate<String, Object> template() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new JdkSerializationRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
#Bean
public ChannelTopic topic() {
return new ChannelTopic("common-channel");
}
#Bean
public MessageListenerAdapter messageListenerAdapter() {
return new MessageListenerAdapter(new Receiver());
}
#Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.addMessageListener(messageListenerAdapter(), topic());
return container;
}
Unit Testing Receiver and Publisher implementation is quite straight.
JUnit 5 coupled with Mockito extension should do the job.
For example for testing that :
public String publish(Object domainObj) {
template.convertAndSend(topic.getTopic(), domainObj.toString());
return "Event Published";
}
I expect that topic and template be fields of the current class.
These fields could be set by constructor.
So you could write something that check that convertAndSend() is eventually executed with the correct parameters :
#Mock
RedisTemplate<String, Object> templateMock;
#Test
void publish(){
Topic topicFixture = new Topic(...);
Object domainObjFixture = new FooBar(...);
Publisher publisher = new Publisher(templateMock, topicFixture);
//when
publisher.publish(domainObjFixture);
// then
Mockito.verify(templateMock)
.convertAndSend(topicFixture.getTopic(), domainObjFixture);
}
But I don't think that the unit test of these two classes be enough because it never tests the final things : the JMS processing performed by Redis backend.
Particularly, the RedisConfig part that you set with specific things as serializers that have important side effects on the processing.
For my part, I try to always write integration or partial integration tests for Redis backend stuffs to ensure a good no regression harness.
The java embedded-redis library is good for that. It allows to start a redis server
on localhost (works on Windows as well as on Linux).
Starting and stopping the redis server is as simple as :
RedisServer redisServer = new RedisServer(6379);
redisServer.start();
// do some work
redisServer.stop();
Move the start() in the #BeforeEach and the stop() in the #AfterEach and the server is ready.
Then it still requires some adjustments to ensure that the redis configuration specified in Spring is well setup during the tests while using your local redis server and not the "real" redis server. Not always simple to set but great when it is done !
The simplest way to unit test this is to use embedded-redis module. What you do is in BeforeAll you can start embedded Redis and stop the embedded Redis in AfterAll method.
You can also PostConstruct PreDestroy annotations to accomplish this.
If you're looking for Junit5 then you can find the code in my repo here
See BootstrapRedis annotation and their usage here
https://github.com/sonus21/rqueue/blob/7ef545c15985ef91ba719f070f7cc80745525047/rqueue-core/src/test/java/com/github/sonus21/rqueue/core/RedisScriptFactoryTest.java#L40

How to write Junit for a service component class using webtestclient in Spring 5

I'm using Springboot2, Spring5 and reactive-webflux in my Java microservices.
I have a service class which I want to test using webtestclient:-
#Service("authenticationProvider")
public class CommonAuthenticationProvider implements AuthenticationProvider {
#Override
public AccessToken getUserAccessToken(Tuple2<String, WebClient> serviceConnectionDetails, MultiValueMap<String, String> queryParams) {
return serviceConnectionDetails._2
.post()
.uri(builder -> builder
.path(serviceConnectionDetails._1)
.queryParams(queryParams)
.build())
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
.retrieve()
.bodyToMono(AccessToken.class)
.block();
}
}
Here serviceConnectionDetails._2 is a webclient instance. I want to write a JUnit test to mock this webclient and test the method getUserAccessToken(). Please assist as I had tried many things like mockmvc, mockRestServiceServer but nothing worked. Later I came to know that, I cannot user mockRestServiceServer since it used to mock RestTemplate and not WebClient. I can test controller class methods using webtestclient but not this at service class
This should be supported in a future Spring Framework version with MockRestServiceServer; see SPR-15286.
For now, the only solution is to use a separate library for that, such as okhttp's MockWebServer.

jackson-dataformat-xml turns #ResponseBody to XML

So I had a perfectly working Spring app. Most of my controller methods are for ajax calls that return JSON via #ResponseBody with the jackson api and returns my Java POJO to JSON.
I have a need to turn XML to JSON, so I find that Jackson has a tool for that, and I add this to my POM to use the library:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.0</version>
</dependency>
So that I may use this:
XmlMapper xmlMapper = new XmlMapper();
JsonNode node = xmlMapper.readTree(sb.toString().getBytes());
But now the #ResponseBody is returning XML and not JSON. I Remove the dependency and the controllers return JSON again.
Any way to get both? I want the xmlMapper, and JSON from the response body.
jackson-dataformat-xml appears to be registering a MappingJackson2HttpMessageConverter with a XmlMapper, along with other HttpMessageConverters that work with XML. If you always intended to return JSON from your controllers, you can change what HttpMessageConverter your app uses by overriding configureMessageConverters
For Spring 5.0 and above,
#Configuration
public class HttpResponseConfig implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> supportsXml(converter) || hasXmlMapper(converter));
}
private boolean supportsXml(HttpMessageConverter<?> converter) {
return converter.getSupportedMediaTypes().stream()
.map(MimeType::getSubtype)
.anyMatch(subType -> subType.equalsIgnoreCase("xml"));
}
private boolean hasXmlMapper(HttpMessageConverter<?> converter) {
return converter instanceof MappingJackson2HttpMessageConverter
&& ((MappingJackson2HttpMessageConverter)converter).getObjectMapper().getClass().equals(XmlMapper.class);
}
}
For older versions of Spring, replace implements WebMvcConfigurer with extends WebMvcConfigurerAdapter
Add Accept: application/json to HTTP request header.
Read this for an analysis of how Spring does content negotiation and allows producing either XML or JSON.
The simplest way is to add an extension at the URL: Instead of /path/resource use /path/resource.json
You may also add a format parameter e.g. /path/resource?format=json or pass an appropriate Accept header
In my case, the XmlMapper was actually inserted into the application context as an #Bean. The other solutions here did not work for me. It seems like one of those issues where context matters, so for people coming here from a different context than the other answerers, here's another angle: I had to insert my own ObjectMapper.
#Configuration
public class XmlMapperConfiguration {
#Bean // me, culprit
public XmlMapper xmlMapper() {
return new XmlMapper();
}
#Bean // to make sure the rest of the application still works with JSON
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}
I'm going to throw in an #Primary on the ObjectMapper one. It seems suspicious that Spring would even choose that one consistently. Since XmlMapper extends ObjectMapper, why would it not take that one, so #Primary won't hurt.

Custom ExceptionMapper for Jersey not working for invalid JSON input

I have the following resource that consumes a JSON being mapped to a POJO.
#Path("example")
public class ExampleResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response addThesis(MyObject myObject) {
return Response.ok().entity("Test").build();
}
}
Here's the POJO class:
public class MyObject {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
When I send a POST request with the body {"title":"Test title"} everything works fine. The response is Test, as expected. However, when I change the request to {"titlee":"Test title"} the server replies with this:
Unrecognized field "titlee" (class com.my.package.MyObject), not marked as ignorable (one known property: "title"])
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#6dc6a46a; line: 2, column: 11] (through reference chain: com.my.package.MyObject["titlee"])
Obviously this is an exception thrown and returned by Jersey. How can I intercept this exception and return a custom status code and message?
What I've tried so far is to implement my own ExceptionMapper:
#Provider
public class MyJsonExceptionMapper implements ExceptionMapper<JsonProcessingException> {
public Response toResponse(JsonProcessingException e) {
return Response.status(400).entity("JSON Processing Error").build();
}
}
Unfortunately the response stays the same. When I implement an ExceptionMapper for a custom exception and throw the corresponding exception in the resource method though, everything works fine. I assume this has to do with the default ExceptionMapper for JsonProcessingException overriding my own one. Then I tried to create a generic mapper ("implements ExceptionMapper"), but again no success.
I've looked literally everywhere and tried many things including extending ResourceConfig and registering my mapper, but nothing has worked so far.
Some more information that might help to narrow the problem down: I am using Grizzly2 as the HTTP server which I am deploying as a Fat JAR.
The dependency part of my pom.xml looks like this:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.24</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.24</version>
</dependency>
</dependencies>
Any advice is highly appreciated.
Ok, this is dumb and hack-ish, but worked for me:
register(JacksonJaxbJsonProvider.class);
This is due to the following "nice default behavior" in the Jackson feature entry point:
if (!config.isRegistered(JacksonJaxbJsonProvider.class)) {
// add the default Jackson exception mappers
context.register(JsonParseExceptionMapper.class);
context.register(JsonMappingExceptionMapper.class);
:(
But, I'd still prefer an answer that fixes the problem "for real" - ie. without pre-registering components so that the feature cannot configure them properly...
I also faced this issue. If JacksonFeature is registered, you can simply register JacksonJaxbJsonProvider as a workaround.
When the JacksonFeature is in the classpath, it is automatically discovered by Jersey. Another approach to fix it is disabling auto discovery by setting ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE to true. As a result of this, you would need to register other features manually.
Alternatively you can get rid of the jersey-media-json-jackson artifact and use jackson-jaxrs-json-provider instead. With this, you will get rid of JacksonFeature and then you can register your own exception mappers.
One last option and probably what seems to be the correct solution (as pointed in Kysil Ivan's answer) you can write your own exception mapper and then give it a high priority, such as 1. If you use auto discovery, just annotate it with #Provider and #Priority:
#Provider
#Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
...
}
If you manually register your provider, you can give your provider a binding priority:
#ApplicationPath("/")
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(JsonParseExceptionMapper.class, 1);
}
}
See this answer for more details.
We use JAX-RS on Wildfly to implement our web services and use the following to accomplish what you are trying to do with Jersey on Glassfish. Maybe it has similar features which you could look up. Our steps are:
The service is a stateless EJB, use EJB interceptor to trap exception
and populate request scoped object with details
Implement a PostProcessInterceptor which reads from request scoped object and modifies response before service returns. (This is specific to JAX-RS)

Does Spring Support JSON Configuration?

Does anyone know if Spring has any extensions that allow for configuring its ApplicationContext via JSON (or really any other format) rather than XML? I couldn't find anything in the official docs, but I was wondering if there were any other open source extensions that could allow this.
Just to be clear, I'm not talking about configuring SpringMVC to set up a RESTful JSON-based web service or anything like that, just if it's possible to do Spring app configuration via JSON instead of XML.
As far as I know there is no project to support JSON as configuration source. It should be relatively easy to kick-start, (Spring container has no dependency on XML, it is just a way to construct bean definitions). However it is much more work than you might think.
Note that Spring provides xml-schema to assist you in writing correct XML. You won't get that much in JSON. Also many DSLs were built on top of Spring XML and custom namespaces support (spring-integration, mule-esb and others use it).
If you hate XML (many do), try out Java Configuration, available since 3.0 and improved in 3.1:
#Configuration
public class MyBeans {
#Bean
public Foo foo() {
return new Foo();
}
#Bean
public Bar bar() {
return new Bar(foo());
}
#Bean
public Buzz buzz() {
Buzz buzz = new Buzz();
buzz.setFoo(foo());
return buzz;
}
}
Interesting fact: thanks to some fancy proxying, foo() is called exactly once here, even though referenced twice.
Try JSConf library available on maven central, it's support Properties, HOCON and JSON format.
You can inject values from external file to your service and more !
Sample usage of JavaConfig :
You data stored on file app.conf
{
"root":{
"simpleConf":{
"url":"Hello World",
"port":12,
"aMap":{
"key1":"value1",
"key2":"value2"
},
"aList":[
"value1",
"value2"
]
}}
You service where your configuration must be inject
#Service("service")
public class Service {
#Autowired
private ConfigBean configBean;
}
Declare a interface to access your configuration values from your service
#ConfigurationProperties("root/simpleConf")
public interface ConfigBean {
String getUrl();
int getPort();
Map getAMap();
List getAList();
}
And your Spring configuration bean :
#Configuration
public class ContextConfiguration {
#Bean
public static ConfigurationFactory configurationFactory() {
return new ConfigurationFactory().withResourceName("app.conf") //
.withScanPackage("org.jsconf.core.sample.bean");
}
}