What is the best way of replace CXF's JSONProvider (Jettison based) with MOXy? - json

I was wondering why MOXy is not providing a JSONProvider class similar to JACKSON to replace the default JSON provider in a jax-rs implementation?
This would be the easiest way to deal with all classes in a certain package.
What I ended up doing was to do the following as I feel that custom context resolver or MessageBodyWriter/Reader are mostly suited to handle certain classes, but not to handle all classes in a package especially if you have many classes.
Am I right?
What are your thoughts?
What is the best way to replace Jettison with MOXy in CXF to handle all classes in a package?
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.apache.cxf.jaxrs.provider.json.JSONProvider;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class MyJSONProvider<T> extends JSONProvider<T> {
private static JAXBContext jaxbContext = null;
static {
try {
jaxbContext = JAXBContextFactory.createContext("com.bp.bs", null);
} catch (JAXBException jaxbe) {
jaxbe.printStackTrace();
throw new ExceptionInInitializerError(jaxbe);
}
}
#Override
public void writeTo(T obj, Class<?> cls, Type genericType,
Annotation[] anns, MediaType m,
MultivaluedMap<String, Object> headers, OutputStream os)
throws IOException, WebApplicationException {
Marshaller marshaller = null;
try {
marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE,
"application/json");
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.marshal(obj, os);
} catch (JAXBException jaxbe) {
jaxbe.printStackTrace();
}
}
}

EclipseLink JAXB (MOXy) offers the org.eclipse.persistence.jaxb.rs.MOXyJsonProvider class that can be used to enable it as the JSON-provider.
Below is an example of a JAX-RS Application class that configures MOXyJsonProvider.
package org.example;
import java.util.*;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
public class CustomerApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(2);
set.add(MOXyJsonProvider.class);
set.add(CustomerService.class);
return set;
}
}
MOXyJsonProvider was added in EclipseLink 2.4.0. The latest version is EclipseLink 2.4.1 which can be downloaded from the following link:
http://www.eclipse.org/eclipselink/downloads/
For More Information
http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html

Related

org.mockito.MockingDetails.getMockHandler()Lorg/mockito/invocation/MockHandler

I want to write the Unit test using PowerMockito/Mockito for my static method/void method.
But When I try to run , I got the following error:
/Users/<username>/Library/Java/JavaVirtualMachines/corretto-
---- IntelliJ IDEA coverage runner ----
sampling ...
include patterns:
exclude patterns:
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider jdk.nashorn.api.scripting.NashornScriptEngineFactory not a subtype
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider jdk.nashorn.api.scripting.NashornScriptEngineFactory not a subtype
java.lang.NoSuchMethodError: org.mockito.MockingDetails.getMockHandler()Lorg/mockito/invocation/MockHandler;
at org.powermock.api.mockito.invocation.MockHandlerAdaptor.getMockHandler(MockHandlerAdaptor.java:56)
at org.powermock.api.mockito.invocation.MockHandlerAdaptor.createInvocation(MockHandlerAdaptor.java:81)
at org.powermock.api.mockito.invocation.MockHandlerAdaptor.performIntercept(MockHandlerAdaptor.java:61)
at org.powermock.api.mockito.invocation.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:93)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:186)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:168)
at org.powermock.core.MockGateway.methodCall(MockGateway.java:138)
I am new to use powerMockito/Mockito, Can Anyone help to figure out the exact issue.
This is my CreateTaskBuilder Class method that I want to test:
Here JgitAccessor.clone() is a static void methid that I used donothing() for it.
public void Repository() throws DependencyFailureException, IOException, GitAPIException {
try {
ServiceAccessor.loadTmpSshTicket();
if (!Files.exists(Paths.get(LambdaEnv.GIT_SSH_SCRIPT.getValue()))) { // getValue will throw exception on null
throw new IllegalStateException(String.format("Environment variable GIT_SSH points to file %s but it doesn't exist.",
LambdaEnv.GIT_SSH_SCRIPT.getValue()));
}
JgitAccessor.clone(REPO_URI, CLONED_REPO_PATH);
} catch (IOException | DependencyFailureException e) {
log.info("Exception occurred while performing Service client integration. exception: [{}]", e.getMessage());
e.printStackTrace();
}
}
And this is the unit test class :
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.mockito.Mockito.*;
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"javax.management.*"})
#PrepareForTest({CreateTaskBuilder.class, LambdaEnv.class, ServiceAccessor.class, JgitAccessor.class})
public class CreateTaskBuilderTest extends TestUtils {
#Mock
private ServiceAccessor serviceAccessor;
#Mock
private JgitAccessor jgitAccessor;
#InjectMocks
CreateTaskBuilder builder;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void loadServiceTicket_happyCase() throws Exception {
doNothing().when(serviceAccessor).loadTmpSshTicket();
PowerMockito.mockStatic(System.class);
Mockito.when(System.getenv("GIT_SSH")).thenReturn("/tmp/ssh.sh");
PowerMockito.mockStatic(Files.class);
Mockito.when(Files.exists(Paths.get("/tmp/ssh.sh"))).thenReturn(true);
PowerMockito.mockStatic(JgitAccessor.class);
PowerMockito.doNothing().when(JgitAccessor.class, "clone", Mockito.anyString(), Mockito.anyString());
builder.cloneRepository();
}
I am using Mockito = 2.28.x; PowerMockMockito = 2.x;
It looks like you have the wrong versions of libraries on your classpath.
The version of PowerMock you are using requires a Mockito with an org.mockito.MockingDetails.getMockHandler() which is not available in Mocktio 2.8.x. You can find it in a later version in 2.23.x.
Looking at minimum version dependencies for powermock-api-mockito2 version 2.0.0 you should be using mockito version 2.23.0 or later.
So looks like you need to update Mockito to a later version compatible with your PowerMock version, 2.23.x or later instead of 2.8.x.

Metric in micrometer in URI template . Some path variable needs to be replaced from URL

I want to collect metrics for particular REST API
Suppose I have a URL like /company/{companyName}/person/{id}
Is it possible to collect metrics across
/company/test/person/{id}
/compaby/test2/person/{id}
There's no out-of-the-box support for it but you can provide your own WebMvcTagsProvider to implement it via a Spring bean.
Note that it could lead to tag explosion and end up with OOM if there's any possibility to companyName path variable explosion by a mistake or attack.
In case you are using Spring and RestTemplate for http call, you can register MetricsClientHttpRequestInterceptor with your RestTemplate .
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
#AutoConfigureAfter({MetricsAutoConfiguration.class})
public class RestClientMetricConfiguration {
private final ApplicationContext applicationContext;
#Autowired
public RestClientMetricConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#PostConstruct
public void init() {
MetricsRestTemplateCustomizer restTemplateCustomizer =
applicationContext.getBean(MetricsRestTemplateCustomizer.class);
applicationContext.getBeansOfType(RestTemplate.class).values().forEach(restTemplateCustomizer::customize);
}
}
And use Below method provided by spring RestTemplate to make http call.
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, #Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
Type type = responseType.getType();
RequestCallback requestCallback = this.httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(type);
return (ResponseEntity)nonNull(this.execute(url, method, requestCallback, responseExtractor, uriVariables));
}

How to overcome "Conflicting setter definitions for property "?

I use com.fasterxml.jackson and io.swagger libraries. In my REST endpoint I use org.javamoney.moneta.Money type for a GET query. When deploying the war i get following exception 1;
I have followed this reference and wrote following code[2]; and registered it at #ApplicationPath. But still getting same issue.
Any guide would be really helpful?
#ApplicationPath("/rest")
public class RestApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
set.add(com.test.JsonMoneyProvider.class);
[2]
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import javax.money.MonetaryAmountFactory;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.annotation.XmlTransient;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
#Provider
public class JsonMoneyProvider extends JacksonJsonProvider {
public JsonMoneyProvider() {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(MonetaryAmountFactory.class, MixIn.class);
setMapper(mapper);
}
public static interface MixIn {
#JsonIgnore
#XmlTransient
MonetaryAmountFactory setCurrency(CurrencyUnit currency);
#JsonIgnore
#XmlTransient
default MonetaryAmountFactory setCurrency(String currencyCode) {
return setCurrency(Monetary.getCurrency(currencyCode));
}
}
}
1
Caused by: java.lang.IllegalArgumentException: Conflicting setter definitions for property "currency": javax.money.MonetaryAmountFactory#setCurrency(1 params) vs javax.money.MonetaryAmountFactory#setCurrency(1 params)
at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getSetter(POJOPropertyBuilder.java:293)
at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:246)
at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:127)
at io.swagger.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:99)
at io.swagger.jackson.ModelResolver.resolveProperty(ModelResolver.java:106)
a
Simply use this annotation on the deserialization setter method to indicate Jackson wich one to use: #com.fasterxml.jackson.annotation.JsonSetter

How to test #Valid

In my entities I have some hibernate annotations for validation, like #NotEmpty, #Pattern.. and others
In my controller, on save action, it has an #Valid parameter.
But if any entity has any required field, and there is no annotation I will have problems.
So I would like to test each entity, to ensure they have the necessary notes.
Something like:
#Test(expect=IllegalArgumentException.class)
public void testAllNull() {
Person p = new Persson(); // Person name has an #NotEmpty
validator.validate(p);
}
But how to validate it? Who is called to check #Valid?
Thanks.
I found out how to check:
#Autowired
private LocalValidatorFactoryBean validator;
...
validator.validateProperty(object, propertyName)
Here is a Spring v4.1.x based example of a test validating presence and processing of the #Valid annotation and building of custom JSON response in case of an error.
jUnit
import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import javax.inject.Inject;
import java.util.List;
import static org.abtechbit.miscboard.util.JsonUtils.toJson;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
RegistrationValidationTest.MockDependencies.class,
})
public class RegistrationValidationTest {
#Inject
MockMvc mvc;
#Test
public void validatesRegistration() throws Exception {
Registration registration = ... //build an invalid Registration object
MvcResult result = mvc.perform(post(RegistrationController.CONTEXT_REGISTER).
contentType(MediaType.APPLICATION_JSON).
content(toJson(registration))).
andExpect(status().isBadRequest()).
andExpect(content().contentType(MediaType.APPLICATION_JSON)).
andReturn();
assertThat(result.getResolvedException(), is(notNullValue()));
String content = result.getResponse().getContentAsString();
assertThat(content, is(notNullValue()));
List<Message> messages = JsonUtils.fromJson(content, new TypeReference<List<Message>>() {
});
assertThat(messages.size(), is(1));
}
public static class MockDependencies {
#Bean
public MockMvc mvc() {
return MockMvcBuilders.standaloneSetup(new RegistrationController()).build();
}
}
}
Controller
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
#Controller
public class RegistrationController
{
public static final String CONTEXT_REGISTER = "/register";
#RequestMapping(value = CONTEXT_REGISTER, method = RequestMethod.POST)
#ResponseBody
public String register(#RequestBody #Valid Registration registration) {
//perform registration
}
#ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<List> handleValidationException(MethodArgumentNotValidException ex) {
//Build a list of custom Message{String message;} objects
List<Message> messages = ex.getBindingResult().getAllErrors().
stream().map(e->new Message(e.getDefaultMessage())).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_JSON).body(messages);
}
}
Spring MVC Test Framework might be a good choice. By using this, you can be assured that validations in your tests runs codes as Spring #MVC actually works.
Actually, the #Valid annotation is detected by HandlerMethodInvoker, which processes annotations on the handler methods of Spring controllers. Internally, the actual validation logic is delegated to the Validator bean depending on your application context settings. (Hibernate Validator is widely used.)
By default configuration (e.g. <mvc:annotation-driven />), LocalValidatorFactoryBean is used internally to process #Valid annotation as #Falci noted, but it may differ time to time. Instead, Spring MVC Test Framework provides the same environment as the main application uses, hence a good choice.

Grails Date unmarshalling

If I get the following json from a RESTful client, how do I elegantly unmarshal the java.util.Date? (Is it possible without providing (aka. hard-coding) the format, that's what I mean by elegantly...)
{
"class": "url",
"link": "http://www.empa.ch",
"rating": 5,
"lastcrawl" : "2009-06-04 16:53:26.706 CEST",
"checksum" : "837261836712xxxkfjhds",
}
The cleanest way is probably to register a custom DataBinder for possible date formats.
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CustomDateBinder extends PropertyEditorSupport {
private final List<String> formats;
public CustomDateBinder(List formats) {
List<String> formatList = new ArrayList<String>(formats.size());
for (Object format : formats) {
formatList.add(format.toString()); // Force String values (eg. for GStrings)
}
this.formats = Collections.unmodifiableList(formatList);
}
#Override
public void setAsText(String s) throws IllegalArgumentException {
if (s != null)
for (String format : formats) {
// Need to create the SimpleDateFormat every time, since it's not thead-safe
SimpleDateFormat df = new SimpleDateFormat(format);
try {
setValue(df.parse(s));
return;
} catch (ParseException e) {
// Ignore
}
}
}
}
You'd also need to implement a PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import grails.util.GrailsConfig;
import java.util.Date;
import java.util.List;
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry reg) {
reg.registerCustomEditor(Date.class, new CustomDateBinder(GrailsConfig.get("grails.date.formats", List.class)));
}
}
and create a Spring-bean definition in your grails-app/conf/spring/resources.groovy:
beans = {
"customEditorRegistrar"(CustomEditorRegistrar)
}
and finally define the date formats in your grails-app/conf/Config.groovy:
grails.date.formats = ["yyyy-MM-dd HH:mm:ss.SSS ZZZZ", "dd.MM.yyyy HH:mm:ss"]
Be aware that the new version of Grails 2.3+ supports this type of feature out of the box.
See Date Formats for Data Binding
With that said, if you are forced to use a version of Grails prior to 2.3, the CustomEditorRegistrar
can be updated using the following code to eliminate the deprecation warning, and also uses the #Component annotation, which allows you to remove / skip the step of adding the bean directly in resources.groovy.
Also not that I changed the grails configuration property name to grails.databinding.dateFormats, which matches the property now supported in Grails 2.3+. Finally, my version is a .groovy, not .java file.
import javax.annotation.Resource
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
import org.springframework.stereotype.Component
#Component
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
#Resource
GrailsApplication grailsApplication
public void registerCustomEditors(PropertyEditorRegistry reg){
def dateFormats = grailsApplication.config.grails.databinding.dateFormats as List
reg.registerCustomEditor(Date.class, new CustomDateBinder(dateFormats))
}
}