Here is the example of the code that I use:
#Stateless
#Path("/rest")
public class MyResouce{
#POST
#Path("/test")
public Response test(#Valid Test t){
return Response.ok().build();
}
}
public class Test {
#Size(max = 3)
private String val;
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
}
I expect a ValidationException when I pass an invalid object (length of val more than 3) but the exception doesn't occur. When I inject the validator and to do validation programmatically:
#Path("/rest")
public class MyResouce{
#Resource
private Validator validator;
#POST
#Path("/test")
public Response test(#Valid Test t){
Set<ConstraintViolation<Test>> violations = validator.validate(t); // size = 1, means t object is invalid
return Response.ok().build();
}
}
the result of the validation has 1 ConstraintViolation item that means the object is invalid and it looks like the annotation #Valid is ignored. How to validate objects non programmatically?
Here is my validation.xml descriptor:
<?xml version="1.0" encoding="UTF-8"?>
<validation-config
xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd">
</validation-config>
Websphere version 8.5.5.11, JAX-RS 1.1
JAX-RS 1.1 does not automatically integrate with Bean Validation, so you would be required to perform your own validation (as you did in your second example).
JAX-RS 2.0 (available in WebSphere v9) or 2.1 (available in WebSphere Liberty) both support automatic integration with bean validation. You can find more info on this post.
Hope this helps, Andy
Related
I am writing a JUnit test case for the controller in my micronaut application. The controller has a GET endpoint which invokes a method in my service class. I am getting a NullPointerException so I am assuming that my service class might not be properly mocked however, I am not sure. I am using #Mock (Mockito) for the service.
Am I using the correct annotation to mock the service layer? I have tried to search on google but it hasn't given me much to look into. Thanks.
#MicronautTest
public class FPlanControllerTest {
private static final String url = "dummy_url";
#Inject
FPlanService fplanService;
#Inject
#Client("/")
RxHttpClient client;
#Test
public void testGetLayout() {
FPlanUrl expectedFPlanUrl = new FPlanUrl(url);
when(fplanService.getLayoutUrl(Mockito.anyString(), Mockito.anyString()))
.thenReturn(expectedFPlanUrl);
FPlanUrl actualFPlanUrl = client.toBlocking()
.retrieve(HttpRequest.GET("/layout/1000545").header("layoutId", "7"), FPlanUrl.class);
assertEquals(expectedFPlanUrl , actualFPlanUrl);
}
#MockBean(FPlanService.class)
FPlanService fplanService() {
return mock(FPlanService.class);
}
}
I received the below error.
java.lang.NullPointerException at com.apartment.controller.FPlanControllerTest.testGetLayout(FPlanControllerTest.java:44)
Use #MockBean (io.micronaut.test.annotation.MockBean).
Docs - https://micronaut-projects.github.io/micronaut-test/latest/guide/#junit5
Simply try to mock as below :-
#MockBean(MyService.class)
MyService myService() {
return mock(MyService.class);
}
Now the service can be injected as:-
#Inject
private MyService myService;
Use inside your test method as:-
#Test
public void myServiceTest() {
when(myService.foo(any())).thenReturn(any());
MutableHttpResponse<FooResponse> response = controller.bar(new
MyRequest());
Assertions.assertNotNull(response);
}
I figured out what went wrong. This was giving a NullPointerException because the HTTP response was expecting a String and not the FPlanUrl object. The correct code is as below:
#Test
public void testGetLayout() {
FPlanUrl expectedFPlanUrl = new FPlanUrl("http://dummyurl.com");
when(fplanService.getLayoutUrl(Mockito.anyString(), Mockito.anyString()))
.thenReturn(expectedFPlanUrl);
Assertions.assertEquals("{\"url\":\"http://dummyurl.com\"}", client.toBlocking().retrieve(HttpRequest.GET("/layout/123").header("layoutId", "7"), String.class);
verify(fplanService).getLayoutUrl("123","7");
}
In RestEasy 3.0.16.Final version PreProcessInterceptor interface is deprecated. So what is the proper replacement of this interface. In jboss eap 7 RestEasy version 3.0.16.Final is used.
Old code -
#Provider
#ServerInterceptor
#SecurityPrecedence
public class AbcInterceptor implements PreProcessInterceptor
{
public ServerResponse preProcess(final HttpRequest httpRequest, ResourceMethod resourceMethod) throws Failure,
WebApplicationException {
// auth logic
}
}
New code -
#Provider
#ServerInterceptor
#SecurityPrecedence
public class AuthenticationInterceptor
{
public ServerResponse preProcess(HttpRequest httpRequest, ResourceMethodInvoker method)
throws Failure, WebApplicationException {
// auth logic
}
}
The org.jboss.resteasy.spi.interception.PreProcessInterceptor interface is replaced by the javax.ws.rs.container.ContainerRequestFilter interface in RESTEasy 3.x.
So, you can can use the ContainerRequestFilter for the same.
I am preparing a ReSTful service which I would like to have documented using RAML (and perhaps Swagger as well), but it seems that I cannot implement both JAX-RS and RAML in the same application at the same time.
I have created an Application class for JAX-RS as follows:
public class Application extends javax.ws.rs.core.Application {
#Override
public Set<Class<?>> getClasses() {
// Use the reflections library to scan the current package tree for
// classes annotated with javax.ws.rs.Path and add them to the JAX-RS
// application
Reflections reflections = new Reflections(this.getClass().getPackage().getName());
return reflections.getTypesAnnotatedWith(Path.class);
}
}
I attach the JAX-RS Application object as follows:
Component component = new Component();
Server server = new Server(Protocol.HTTP, PORT);
component.getServers().add(server);
JaxRsApplication jaxRsApplication = new JaxRsApplication(component.getContext().createChildContext());
jaxRsApplication.add(new Application());
jaxRsApplication.setObjectFactory(objectFactory);
component.getDefaultHost().attach("/rest", jaxRsApplication);
And I would also like to implement the RAML extension, but it looks like it is tied to the Restlet Router and having it's own Application class. Is there a way to combine the two?
Indeed the RAML extension of Restlet isn't designed to be used within JAXRS application. That said you can define a resource that provide the RAML content based on classes ApplicationIntrospector of Restlet and RamlEmitter of RAML parser, as described below:
public class RamlResource {
private Definition definition;
#Path("/raml")
#GET
public String getRaml() {
return new RamlEmitter().dump(RamlTranslator
.getRaml(getDefinition()));
}
private synchronized Definition getDefinition() {
if (definition == null) {
synchronized (RamlResource.class) {
definition = ApplicationIntrospector.getDefinition(
Application.getCurrent(),
new Reference("/"), null, false);
}
}
return definition;
}
}
It's the way the RAML extension of Restlet works. You could also use such an approach for Swagger but be careful since Swagger 1.2 requires several resources (a main and several sub ones with each categories). It's not the case anymore for Swagger 2.
You can notice that there is a JAX-RS support for Swagger in the extension org.restlet.ext.swagger.
----- Edited
Perhaps can you make a try with this class that corresponds to a port of the class JaxRsApplicationSwaggerSpecificationRestlet to RAML. It's based on the class JaxRsIntrospector which seems relevant for JAX-RS application:
public class JaxRsApplicationRamlSpecificationRestlet extends Restlet {
private Application application;
private String basePath;
private Reference baseRef;
private Definition definition;
public JaxRsApplicationRamlSpecificationRestlet(Application application) {
this(null, application);
}
public JaxRsApplicationRamlSpecificationRestlet(Context context, Application application) {
super(context);
this.application = application;
}
public void attach(Router router) {
attach(router, "/api-docs");
}
public void attach(Router router, String path) {
router.attach(path, this);
router.attach(path + "/{resource}", this);
}
public Representation getApiDeclaration() {
Raml raml = RamlTranslator.getRaml(
getDefinition());
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
try {
return new StringRepresentation(
mapper.writeValueAsString(raml),
MediaType.APPLICATION_YAML);
} catch (Exception ex) {
return new StringRepresentation("error");
}
}
public String getBasePath() {
return basePath;
}
private synchronized Definition getDefinition() {
if (definition == null) {
synchronized (JaxRsApplicationRamlSpecificationRestlet.class) {
definition = JaxRsIntrospector.getDefinition(application,
baseRef, false);
}
}
return definition;
}
#Override
public void handle(Request request, Response response) {
super.handle(request, response);
if (Method.GET.equals(request.getMethod())) {
response.setEntity(getApiDeclaration());
} else {
response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
}
}
public void setApiInboundRoot(Application application) {
this.application = application;
}
public void setApplication(Application application) {
this.application = application;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
// Process basepath and check validity
this.baseRef = basePath != null ? new Reference(basePath) : null;
}
}
You can use this class like this:
JaxRsApplication application
= new JaxRsApplication(component.getContext());
MyApplication app = new MyApplication();
application.add(app);
new JaxRsApplicationRamlSpecificationRestlet(app);
(...)
There is no need for a dedicated resource. Please note that this code is a bit experimental ;-) I could propose it back for a contribution for the extension raml in Restlet...
Hope it helps you,
Thierry
I use Gucie 3.0 to intercept any methods that have my defined annotation #LogRequired. However for my application, some beans are initialized by Spring with injected fields values. After calling giuce injector.injectMembers(this), the beans gets proxied by guice but all original fields values are gone. Looks like Guice re-constucts the beans and throw away all old values. Is this expected behavior or how can I solve this issue?
Create a class extends AbstractModule
public class InterceptorModule extends AbstractModule{ public void configure()
{ LogInterceptor tracing = new LogInterceptor(); requestInjection(tracing); bindInterceptor(Matchers.any(), Matchers.annotatedWith(LogRequired.class), tracing); }
}
Define the interceptor business logic
public class LogInterceptor implements MethodInterceptor { //business logic here }
Create LogService class
Public class LogService { Injector injector = Guice.createInjector(new InterceptorModule()); }
I have one of the bean example below with the getName method wants to be intercepted:
public class UserImplTwo implements IUser {
private String name;
#LogRequired
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
which is initialized by Spring context:
Finally I have a consumer to consume the bean:
public class Consumer
{
#Inject
private UserImplTwo instance;
public void setInstance(UserImplTwo instance)
{
this.instance = instance;
}
public void init()
{
// the value of name is printed out as 'hello world'
System.out.println( this.instance.getName());
LogService.injector.injectMembers(this);
// the value of name is printed out as null, should be 'hello world'
System.out.println( this.instance.getName());
}
}
Then use Spring to initialized the bean:
<bean id="consumer" class="com.demo.Consumer" init-method="init">
<property name="instance" ref="userTwo"></property>
</bean>
Please let me know if this the the right approach or if I did something wrong, because I have to use Spring to initialize some beans.
A "right approach" is probably to keep things simple and use Spring's DI if you use Spring Framework, and not try to mix and match with Guice :-)
Having said that there seems no technical reason why they can't be mixed and matched together to some degree.
I think you will have more success with another approach. One that I have used before is to make use of Spring MVC Java-based configuration. Here is the basic approach.
Create a class that extends WebMvcConfigurationSupport:
#Configuration
#Import(BeansConfig.class)
public class Config extends WebMvcConfigurationSupport {
}
Separate out your beans config (probably it can be merged with the above but I guess it's quite dull code and you normally don't want want to see it). And use it to create your beans with your Guice injector before providing them to Spring.
#Configuration
public class BeansConfig {
#Bean
public Consumer getConsumer() {
return SomeGuiceInjectorFactory.newInstance(Consumer.class);
}
}
Include this in your spring.xml (or bootstrap other ways if your servlet container is newer than mine was)
<context:annotation-config/>
<bean id="extendedWebMvcConfig" class="Config"/>
Constructor injection and most/all? other Guice goodness should work also with such scenario.
Also you won't need to configure your beans in xml.
Here is my bean that is trying to inject a singleton bean InformationService :
#Path("/information/{name}")
#Stateless (name="InformationResource")
public class InformationResource {
#EJB
private InformationService appService;
#GET
#Produces(MediaType.APPLICATION_XML)
public Information getInfo(#PathParam("name") String name){
return appService.getMap().get(name);
}
#PUT
#POST
#Consumes(MediaType.APPLICATION_XML)
public Information putInfo(#PathParam("name") String name, Information info){
return appService.getMap().put(name,info);
}
#DELETE
public void deleteInfo(#PathParam("name") String name){
appService.getMap().remove(name);
}
}
This is the InformationService class
#Singleton
public class InformationService {
private Map<String,Information> map;
#PostConstruct
public void init(){
map = new HashMap<String,Information>();
map.put("daud", new Information("B.Tech","Lucknow"));
map.put("anuragh", new Information("M.Sc","Delhi"));
}
public Map<String,Information> getMap(){
return map;
}
}
Its part of a very simple JAX-RS implementation and I am deploying as war in JBoss 6.1 Final. The problem is that InformationService throwing a NullPointerException when I make the proper get request. If I initialize appService explicitly, everything works fine. Why is #EJB annotation not working ?
Are you using Jersey as REST implementation? If so, EJB injection is not supported out of the box.
This link provides more information on this and also a solution.
Check that your #Singleton is javax.ejb.Singleton.
Any other exceptions before NPE ?