In one of my projects I've already upgraded Jersey from version 2.14 to 2.23. But I'm struggling many hours with one problem. My project defines its own ExceptionMapper for a ValidationException, but unfortunately Jersey already has a built-in exception mapper for this exception and I cannot override it.
I have registered correctly (I checked it) my own mapper which is presented below:
#Provider
public class ValidationExceptionMapper implements
ExceptionMapper<ValidationException> {
#Override
public Response toResponse(ValidationException exception) {
return Response.status(Status.BAD_REQUEST).build();
}
}
but it is never being called. Jersey always pick up the org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper.
I've also tried to use #Priority annotation for my custom mapper, but unfortunately Jersey doesn't take it into account.
So what is going on? It worked perfectly fine in the previous Jersey version, so it seems to be a regression bug.
I give up. Any clues?
It really turned out to be a regression bug in Jersey, introduced in January 2015.
Bug is related with two Jersey's extensions: for Weld and bean validation.
Because without Weld container started, my custom ValidationExceptionMapper mapper takes precedence over the built-in one provided by the jersey-bean-validation module, so my goal is achieved.
I've filled a bug report under JERSEY-3153, later moved as the issue #3425.
To be honest, I'm never ever going to use Weld + Jersey again... I'm so tired with this combination. Through the last two years I've encountered around 10 bugs already. I'm really tired.
Anyway, I hope it will help somebody.
UPDATE:
As #Justin Jose noticed in the comments below, there is also another workaround for the mentioned bug. We can use HK2 bindings, to override the problematic built-in mapper:
register(new AbstractBinder() {
#Override
protected void configure() {
bind(my.custom.ValidationExceptionMapper.class).to(ExceptionMapper.class)
.in(Singleton.class);
}
});
Jersey's built-in ValidationExceptionMapper is registered via ValidationFeature. Probably, replacing Jersey's ValidationFeature with your own version can do the trick. It can be done as follows.
Firstly, disable auto-discoverable ValidationFeature
property(ServerProperties.BV_FEATURE_DISABLE, true);
Next step is to register a clone of Jersey's validation feature
public static class ValidationFeatureClone implements Feature {
#Override
public boolean configure(FeatureContext context) {
context.register(new ValidationBinder());
context.register(NewValidationExceptionMapper.class);
context.register(ValidationErrorMessageBodyWriter.class);
return true;
}
}
In the clone, you should specify your new ExceptionMapper.
Finally, register your new Feature
register(ValidationFeatureClone.class)
UPDATE:
From Jersey 2.20 onwards, default ValidationExceptionMapper can be overwritten using HK2 binding as shown below.
register(new AbstractBinder() {
#Override
protected void configure() {
bind(NewValidationExceptionMapper.class).to(ExceptionMapper.class)
.in(Singleton.class).ranked(10);
}
});
I found a way to get it to work with newer Jersey releases again, which I also posted under your bug report.
One needs to build Jersey locally with the changed code, specifically the jersey-bean-validation artifact.
Locate org.glassfish.jersey.server.validation.internal.ValidationBinder and comment out the following two lines in configure():
bind(ValidationExceptionMapper.class).to(ExceptionMapper.class).in(Singleton.class);
bind(ValidationErrorMessageBodyWriter.class).to(MessageBodyWriter.class).in(Singleton.class);
It's kind of ironic that the source code comment above those lines says that they're supposed to allow users to register their own providers.
Unfortunately the bug still exists and cause headaches...
In my case easiest solution was providing custom ExceptionMapper specifically for ConstraintViolationException.
public class CVExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(final Throwable t) {
...
}
}
and then registering it as always with:
context.register(CVExceptionMapper.class);
Related
I'm inquiring about the need to proceed with the development of Spring boot 1.X version, but one part is blocked.
I use Embedded Tomcat, so I have to register with #Bean for ErrorReportValue.
I'm working on moving 400 Bad Request to Custom Error page, but I found a way.
However, they are classes that can be applied from Spring 2.X or higher, so they are not applied to Spring 1.4 version.
The replaceable code was similar but failed. What are some ways to get that function to 1.4 as well?
If you look at the code below, there are codes available from Spring 2.X and above. "TomcatWebSocketServletWebServerCustomizer" and "TomcatServletWebServerFactory" .
Because of these two codes, it is not possible to proceed in version 1.X. It would be nice to upgrade the version, but it will be difficult due to the circumstances.
Among the replaceable codes, "TomcatWebSocketContainerCustomizer" and "Tomcat EmbeddedServletContainerFactory" were available, but were not compatible with "StandardHost".
Help me.
Thank you.
#Bean
public TomcatWebSocketServletWebServerCustomizer errorValveCustomizer() {
return new TomcatWebSocketServletWebServerCustomizer() {
#Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addContextCustomizers((context) -> {
Container parent = context.getParent();
if (parent instanceof StandardHost) {
((StandardHost) parent).setErrorReportValveClass("com.java.lmh.errors.CustomError");
}
});
}
#Override
public int getOrder() {
return 100; // needs to be AFTER the one configured with TomcatWebServerFactoryCustomizer
}
};
}
}
I have an application that uses Jersey/JAX-RS for web services (annotations, etc) and Guice to inject service implementations. I don't really like the way Guice works with servlets directly, I prefer the Jersey way, so I had to do a bit of fussing to get the service injections to work since Guice wouldn't be creating my servlet classes, and I didn't want to deal with the HK2-Guice bridge. I did this by creating a listener class (called Configuration) that sets up the injectors in static fields upon application startup and then manually effecting the injections in each servlet class by creating a parent class that all my servlets extend with a constructor that contains the following:
public MasterServlet() {
// in order for the Guice #Inject annotation to work, we have to create a constructor
// like this and call injectMembers(this) on all our injectors in it
Configuration.getMyServiceInjector().injectMembers(this);
Configuration.getDriverInjector().injectMembers(this);
}
I know it's kind of hacky, but this works just fine in my servlets. I can use the Guice #Inject annotations on my services and switch between named implementations and so on. The problem comes when I go to set up my unit tests. I'm using JerseyTest to do my tests, but running a test against my servlets results in a 500 error with Guice saying the following:
com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for com.mycompany.MyService was bound.
while locating com.mycompany.MyService
for field at com.mycompany.servlet.TestGetServlet.service(TestGetServlet.java:21)
while locating com.mycompany.servlet.TestGetServlet
The test looks like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
Configuration configuration = new Configuration();
configuration.contextInitialized(null);
}
#Override
protected Application configure() {
return new ResourceConfig(TestGetServlet.class);
}
}
You'll notice in the setup method I am manually creating my Configuration class since I can't rely on the test container (Grizzly) to create it (I get NullPointerExceptions without those two lines). More about this below.
And here's the servlet being tested:
#Path("/testget")
public class TestGetServlet extends MasterServlet {
#Inject
MyService service;
#GET
#Produces({"text/plain", MediaType.TEXT_PLAIN})
public String testGet() {
//service = Configuration.getServiceInjector().getInstance(MyService.class);
return "get servlet functional";
}
}
Notice the commented line in the testGet() method? If I do that instead and remove the #Inject annotation above, everything works fine, which indicates that Grizzly is not creating my servlets the way I expect.
I think what's happening is that Grizzly doesn't know about Guice. Everything seems to suggest that Grizzly isn't seeing the Configuration class, despite the fact that by putting it in my test's #Before method it seems to be at least available to the classes that use it (see: the commented line in the TestGetServlet class). I just don't know how to fix it.
I'm still trying to figure this out but in the meantime I switched from Guice to HK2, which took a bit of doing but I figured this might be helpful for anyone who runs into this problem in the future.
I consider this an answer because truthfully my attempt to bypass the Guice-HK2 bridge but still use Guice with Jersey might not have been the best idea.
Switching from Guice to HK2 takes a bit of doing and there's no comprehensive guide out there with all the answers. The dependencies are really fussy, for example. If you try to use Jersey 2.27 you may run into the famous
java.lang.IllegalStateException: InjectionManagerFactory not found
error. Jersey 2.27 is not backwards compatible with previous versions due to HK2 itself. I am still working on getting that all to work, but in the meantime I had to downgrade all my Jersey dependencies to 2.26-b06 to get HK2 working properly.
Jersey thankfully already implements a bunch of HK2 boilerplate, so all you need to get injection working is proper use of #Contract, #Service (see HK2 docs for those), and then two new classes that look like this:
public class MyHK2Binder extends AbstractBinder {
#Override
protected void configure() {
// my service here is a singleton, yours might not be, so just omit the call to in()
// also, the order here is switched from Guice! very subtle!
bind(MyServiceImpl.class).to(MyService.class).in(Singleton.class);
}
}
And this:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
Simple enough, but this only works for the application itself. The test container knows nothing about it, so you have to redo the Binder and ResourceConfig yourself in your test class, like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
}
#Override
protected Application configure() {
return new TestServletBinder(TestGetServlet.class);
}
public class TestServletBinder extends ResourceConfig {
public TestServletBinder(Class registeree) {
super(registeree);
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
}
Having to do this is actually fine because you can switch out the Binder for a test binder instead, in which you've bound your service to a mocked service instead or something. I haven't done that here but that's easy enough to do: replace new MyHK2Binder() in the call to register() with one that does a binding like this instead:
bind(MyTestServiceImpl.class).to(MyService.class).in(Singleton.class);
And voila. Very nice. Obviously you could achieve a similar result with Named bindings, but this works great and might even be simpler and more clear.
Hope this helps someone save the hours I spent screwing around to get this working.
Ok, so here's something I've been googling for for hours with no success... Finally i can only hope some Spring-magician reads and answers this question. :)
I'm upgrading an old web application (Spring 2.x-based) to Spring 4.2.x and while adding new features I've decided to completely move away from XML-based config. (Again: i don't want to have any Spring XML files in the project!)
I've converted pretty much everything, but the last thing i can't resolve is finding the correct Java-config counterpart of:
<ws:service id="MySoapService" bean="#ServiceImpl" />
<wss:binding service="#MySoapService" url="/1.0/soap" />
ws/wss namespaces come from:
xmlns:ws="http://jax-ws.dev.java.net/spring/core"
xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
So what i'm trying to do is exporting #WebService annotated classes, but with Java-config instead of XML.
Additional infos:
I've tried using SimpleJaxWsServiceExporter, but that one leaves me with a "java.net.BindException: Address already in use: bind", regardless of what port i'm using...
The application has two servlets: one is a normal Spring MVC Dispatcher for the new REST API and another com.sun.xml.ws.transport.http.servlet.WSSpringServlet which should make the above mentioned JAX-WS service available.
I'm trying to resolve things with pure JAX-WS RI, no CXF or any other library. The application is huge enough already... :(
You can achieve this by injecting your endpoint and the following helper method (note that my approach uses a base class BaseEndpoint for each endpoint):
#Configuration
public WebserviceConfiguration {
#Inject
private FooEndpoint fooEndpoint;
#Bean
public SpringBinding fooEndpoint() throws Exception {
return bind(fooEndpoint, "ws/bar");
}
private SpringBinding bind(BaseEndpoint endpoint, String url) throws Exception {
SpringService springService = new SpringService();
springService.setBean(endpoint);
SpringBinding binding = new SpringBinding();
binding.setService(springService.getObject());
binding.setUrl(url);
return binding;
}
}
Apparently there's no solution (yet?) - after quite a few more hours of googling around, i've found only this ticket:
https://java.net/jira/browse/JAX_WS_COMMONS-134
Looking at its date and status (and by noting the fact that devs didn't even respond to it, even a year has passed), i assume it's safe to state that JAX-WS Commons spring integration will not support Java config in the foreseeable future.
I've been searching for hours to find a solution for my problem but I can't get it to work. I want to inject my Weld-managed service into a ConstraintValidator that is used to validate a User-Object that is posted to my JAX-RS Rest-Service. Everything is deployed to a glassfish 4.1 server.
I have a Service like this
#ApplicationScoped
public class UserService {
}
and I want to inject it into a ConstraintValidator like this
public class UniqueUserNameValidator implements ConstraintValidator<UniqueUserName, ApiUser> {
#Inject
private UserService service;
#Override
public void initialize(UniqueUserName constraintAnnotation) {
}
#Override
public boolean isValid(ApiUser value, ConstraintValidatorContext context) {
return service.getByUserName(value.getUserName()) == null;
}
}
the REST resource looks like this
#Path("users")
#Produces(MediaType.APPLICATION_JSON)
public class UserResource {
#Inject
UserService userService;
#POST
public Response createUser(#Valid ApiUser apiUser) {
ApiRepresentation created = userService.create(apiUser);
return Response.created(createURL(created)).build();
}
}
When I Post a json user object i get the following exception:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=UserService,parent=UniqueUserNameValidator,qualifiers={},position=-1,optional=false,self=false,unqualified=null,173822971)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:947)
at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:902)
at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:977)
at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:968)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173)
I'm aware that jersey uses hk2 as DI provider and the ConstraintValidator is created using the InjectingConstraintValidatorFactory which in return uses the ResourceContext. Since HK2 doe know nothing about my WELD container managed beans it can not inject the proper service when creating the ConstraintValidator.
To fix this I am searching for
a) A way to provide JAX-RS (preferable a pure JAX-RS way without a dependency to jersey) with a custom ConstraintValidatorFactory to create the validator.
or
b) A way to force jersey to use WELD as the DI provider or tell hk2 to pickup all container managed beans WITHOUT manually adding every single bean to hk2.
I have no Idea how to use the bridge proposed here .
I appreciate any help.
Cheers
I also faced this issue with Jersey 2.25.x, Weld 2.4.x and Tomcat 8.x and haven't found a proper solution with #Inject.
As a workaround, I programmatically looked up for the bean instance using:
SomeSortOfBean bean = CDI.current().select(SomeSortOfBean.class).get();
Do you have the possibility to change the underlying JAX-RS implementation for your project?
When I had the same problem, I just switched from Jersey to RestEasy (fully certified JAX-RS implementation). http://resteasy.jboss.org/
Changing the implementation was easy enough: Just include the dependy through your favorite build automation tool (I use gradle):
compile 'org.jboss.resteasy:resteasy-servlet-initializer:3.0.11.Final'
Additionally, to make CDI work, include the resteasy-cdi JAX-RS CDI bridge:
compile 'org.jboss.resteasy:resteasy-cdi:3.0.11.
Lastly if you want the same JSON format, include the resteasy-jackson-provider:
compile 'org.jboss.resteasy:resteasy-jackson-provider:3.0.11.Final'
In the end, switching to resteasy gave me a lot less headache than trying to implement a Jersey fix.
I have a MVC Java configuration but the HandlerInterceptor is not excluding some patterns.
At the line marked with xxx, if
1) I add both addPatterns("/**") and excludePathPatterns("*.ecxld") to the HandlerInterceptor's InterceptorRegistration, the HandlerInterceptor.preHanlde() is NOT invoked at all. e.g .addPathPatterns("/**").excludePathPatterns("*.ecxld")
2) I add only excludePathPatterns("*.ecxld") to the HandlerInterceptor's InterceptorRegistration, the HandlerInterceptor.preHanlde() is still executed.
(the other interceptors are invoked fine).
Any pointers appreciated.
Thanks
#Configuration
public class MyMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(getInterceptorOne());
registry.addInterceptor(getMyHandlerInterceptor())
.excludePathPatterns("*.ecxld"); // **xxx**
registry.addInterceptor(getInterceptorTwo()
);
}
The patterns you specify for include and exclude are ant bases path expressions and not normal URL expressions as you would express in web.xml to map a servlet or filter for instance.
To make an exclude work you have to also include an include path (as you already noticed with your second remark). Next change your exclude pattern to /**/*.ecxld.
Your current expression *.ecxld would match file.ecxld but it will not match /file.ecxld or even /foo/file.ecxld. The /**/ part takes care of that. However to make it work it also requires an includePathExpression (the code checks if there is an includePathExpression when not it is ignoring the excludePathExpression).
So in short change your configuration to the following should solve your problem.
#Configuration
public class MyMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(getInterceptorOne());
registry.addInterceptor(getMyHandlerInterceptor())
.includePathPatterns("/**")
.excludePathPatterns("/**/*.ecxld");
registry.addInterceptor(getInterceptorTwo()
);
}
I know this was a long while ago but I just stumbled over the same problem. During my search I found the following blog. There it is mentioned that if the interceptors are configured as beans they will be automatically added to the chain.
I am now using Spring 4.1.x so there might be a difference but what solved it for me was the following:
(I tried to avoid defining them as a spring beans. It didn't help.)
I configured the interceptors as spring beans (so I could autowire stuff into them see here)
I changed my definition as follows:
registry.addInterceptor(getMyHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/login");
By putting the addPathPatterns before the excludePathPatterns the behavior of the interceptor suddenly worked fine.
After debugging, the interceptors are not executed in the order they were added. In the above example, interceptorOne, then interceptorTwo, then the handler (with the excluded pattern) was executed.
I run into this trouble, can't exclude the path.
After I debug, found out is because Spring security redirect to "/login", because of "/login" is included in "/**", that why cannot access.
Solution is add the login & logout link as exclude paths too!
I've faced a similar problem while working with SpringBoot.
How I solved this problem?
I made a method to return a new instance of the Interceptor. And you will have to write the excludePathPatters after the addPathPattern method of the registry.
Here's the code snippet:
#Bean
public AuthInterceptor getAuthInterceptor() {
return new AuthInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(**getAuthInterceptor()**)
.addPathPatterns("/**")
.excludePathPatterns("/login/**");
}
I hope this helps.