[JERSEY-2664] How to get form parameters from ContainerRequestContext ? Created: 26/Sep/14  Updated: 22/Jul/16  Resolved: 24/Oct/14

Status: Closed
Project: jersey
Component/s: None
Affects Version/s: 2.0
Fix Version/s: None

Type: Bug Priority: Blocker
Reporter: Ankit337 Assignee: Marek Potociar
Resolution: Works as designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jersey-server

 Description   

Why you stop the way to get form parameter at filter level ?

Here is MY QUESTION

MyFilter.java
 @Override
    public void filter(ContainerRequestContext ctx) throws IOException
    {
        MultivaluedMap<String, String> pathparam = ctx.getUriInfo().getPathParameters();
        MultivaluedMap<String, String> quaeryparam = ctx.getUriInfo().getQueryParameters();
      // Here i want all form parameters 
    }    

  • Here i can get pathParam,queryParam from ContainerRequestContext, So how can i get formParam from ContainerRequestContext?

In Jersey 1.x, We can get form parameters like

public class MyFilter implements ContainerRequestFilter {
  public ContainerRequest filter(ContainerRequest request) {
    Form f = request.getFormParameters();

    // examine form data and filter as needed
  }
}

So in Jersey 2.0 how can I get this ?

public class MyFilter implements ContainerRequestFilter {
  public void filter(ContainerRequestContext context) {
    // how do I get to the Form data now?
  }
}


 Comments   
Comment by Adam Lindenthal [ 09/Oct/14 ]

Hi,

the problem is, that the while path and query params are part of the URI and as such can be easily reachable in the context via UriInfo, the form params are part of the entity.

I cannot thing of a clean way how to do that in the request filter.
Right now, I can only thing of a solution to getting a reference to the input stream, reading it and parsing it.

Maybe a ReaderInterceptor or custom MessageBodyReader would be a better solution, but I leave this issue open for a while, so that others can also contribute with their opinions.

Comment by Marek Potociar [ 24/Oct/14 ]

This is a limitation of JAX-RS 2.0 filter API. If you want, you can file a new enhancement request against the JAX_RS_SPEC project. To process the form data in the JAX-RS 2.0 filter you need to work with the entity stream manually at this point (don't forget to buffer the stream!).

In case you are willing to use Jersey APIs, you can use Jersey ContainerRequest to try to get the JAX-RS Form data from the entity:

MyFilter.java
public class MyFilter implements ContainerRequestFilter {
  public void filter(ContainerRequestContext context) {
    if (! ctx instanceof ContainerRequest) {
      // too bad - not using Jersey...
      return;
    }
    ContainerRequest cr = (ContainerRequest) ctx;
    cr.bufferEntity();
    Form form = cr.readEntity(Form.class);
    // ...process form parameters
  }    
}
Comment by bricedutheil [ 22/Jul/16 ]

For reference one can do that without relying on implementation specific classes like Jersey's ContainerRequest. One should rather do that in a portable way like :

AFilter.java
@Provider
public class AFilter implements ContainerRequestFilter {

    @Context
    private Providers providers;

    @Override
    public void filter(ContainerRequestContext request) throws IOException {
        if (!request.hasEntity() || !MediaTypes.typeEqual(APPLICATION_FORM_URLENCODED_TYPE, request.getMediaType())) {
            // if not a form ...
            return;
        }

        ByteArrayInputStream resettableIS = toResettableStream(request.getEntityStream());

        Form form = providers.getMessageBodyReader(Form.class, Form.class, new Annotation[0], APPLICATION_FORM_URLENCODED_TYPE)
                             .readFrom(Form.class, Form.class, new Annotation[0], APPLICATION_FORM_URLENCODED_TYPE, null, resettableIS);

        // do something with Form

        resettableIS.reset();
        request.setEntityStream(resettableIS);
    }

    @Nonnull
    private ByteArrayInputStream toResettableStream(InputStream entityStream) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = entityStream.read(buffer)) > -1) {
            baos.write(buffer, 0, len);
        }
        baos.flush();
        return new ByteArrayInputStream(baos.toByteArray());
    }
}




[JERSEY-2572] Registered ParamConverterProvider for ParamConverter<Date> doesn't work. Created: 02/Jul/14  Updated: 20/Jul/16  Resolved: 05/Aug/14

Status: Closed
Project: jersey
Component/s: None
Affects Version/s: 2.10
Fix Version/s: 2.11

Type: Bug Priority: Major
Reporter: irioth Assignee: Unassigned
Resolution: Invalid Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: Zip Archive test.zip    

 Description   

Jersey internal org.glassfish.jersey.server.internal.inject.ParamConverters.AggregatedProvider overrides all user registered ParamConverterProviders, as result it's impossible to use custom ParamConverter for Date type.



 Comments   
Comment by Miroslav Fuksa [ 02/Jul/14 ]

Hi,

I cannot reproduce your problem. It works fine for me. I have this provider:
public static class MyDateParamProvider implements ParamConverterProvider {

        @Override
        public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
            if (rawType != Date.class) {
                return null;
            }

            return (ParamConverter<T>) new ParamConverter<Date>() {

                @Override
                public Date fromString(String value) throws IllegalArgumentException {
                    final Calendar cal = Calendar.getInstance();


                    cal.set(Calendar.YEAR, 1999);
                    return cal.getTime();
                }

                @Override
                public String toString(Date date) throws IllegalArgumentException {
                    return date.toString();
                }

            };
        }
    }

I register it to the server runtime. I have this resource method:

        @GET
        @Path("date")
        public String getDate(@QueryParam("queryDate") Date query) {
            return query.toString();
        }

and I invoke this test:

@Test
    public void testDate() {
        final Response response = target().path("resource/date").queryParam("queryDate", new Date()).request().get();
        Assert.assertEquals(200, response.getStatus());
        System.out.println("test");
        System.out.println(response.readEntity(String.class));
    }

it prints

test
Fri Jul 02 17:50:17 CEST 1999

So, my converter is invoked and it changes the date to 1999 (simple implementation of my converter just changes the current year to 1999).

Can you attach some reproducible test case? Simple buildable project would be fine (maven project).

thanks
Mira

Comment by irioth [ 02/Jul/14 ]

Sorry for that. It doesn't work if ParamConverterProvider registered via Binder

    public static void main(String[] args) throws Exception {

        Server server = new Server(8080);
        ServletContextHandler handler = new ServletContextHandler();
        handler.addServlet(new ServletHolder(new ServletContainer(new ResourceConfig() {
            {
                register(new AbstractBinder() {
                    
                    @Override
                    protected void configure() {
                        bind(MyDateParamProvider.class).to(ParamConverterProvider.class);
                    }
                });
                
                register(Resource.class);
                
            }
        })), "/*");
        server.setHandler(handler);

        server.start();
    }

Can't attach file You can download sample project from dropbox https://www.dropbox.com/s/bjanmhjemzpldl3/test.zip

Comment by Adam Lindenthal [ 07/Jul/14 ]

Thank you for providing the example. I've attached it to the issue and for now, I'll move it to backlog. It will be planned dor some of the next sprints.

Comment by Adam Lindenthal [ 05/Aug/14 ]

Hi irioth,

I did some investigation and the problem is, that your custom converter provider is on the same priority level as the Jersey's default ParamConverters.AggregatedProvider. You have several options how to work around this.

1. There is a mechanism, that benefits ConverterProviders with custom qualifier, you just need to declare (bind) your converter provider as custom in your binder:
bind(MyDateParamProvider.class).to(ParamConverterProvider.class).in(Singleton.class).qualifiedBy(new CustomAnnotationImpl());
Your provider will have precedence over the AggregatedProvider.
However, as both the @Custom annotation (and its AnnotationLiteral - CustomAnnotationImpl) are in the internal package and are not part of the public API, I do not recommend this. You can create your own hk2 AnnotationLiteral, but still you would depend on the annotation from the internal package (which might be subject to change without prior notice anytime).

2. Hk2 supports provider priorities (ranking), so for instance binding your converter provider in the following way:
bind(MyDateParamProvider.class).to(ParamConverterProvider.class).ranked(10)
will bring you there as well.

3. Your most obvious, most practical and recommended option is not to use AbstractBinder implementation and just register your ParamConverterProvider in the standard way, such as :

ResourceConfig rc = new ResourceConfig();
rc.register(MyDateParamProvider.class);
...

Is there anything preventing you from registering your provider like this? What is the use case for binding it your way?

With regard to the described facts, I have to close the issue. Please let us know your use case and if the suggested solutions work for you or not. Thank you for the bug report anyway - although the behaviour you described won't be changed now, during the testing of your test case, I've found another small bug that will be fixed, so it was useful anyway...

Comment by irioth [ 12/Aug/14 ]

Hi Adam,
Thanks you for detailed response. In our project we use guice bindings and guice-hk2 bridge for integration with jersey. Most providers work without additional registration in ResourceConfig and it allows utilize guice modules concept without additional code. Now i see that it's wrong way and already refactoring code, so that providers explicitly registered in ResourceConfig.

Comment by Adam Lindenthal [ 12/Aug/14 ]

Hi, thank you for writing back - it's better to know what you think about the issue being closed. And for sharing your use case - it is useful to understand your motivation to do the things in a way we consider non-standard. I believe your new approach will be more robust and wish you painless development

Comment by a.accioly [ 22/Nov/14 ]

Hello Adam,

I think that we should reopen this bug.

Reason: Custom ParamConverterProvider doesn’t seem to replace default providers in org.glassfish.jersey.server.internal.inject.ParamConverters.*.
Your third workaround does not work for me. In order to get my custom provider to work I had to use HK2 directly.

Works:

@javax.ws.rs.ApplicationPath("api")
public class ApplicationConfig extends ResourceConfig {
    public ApplicationConfig() {
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(MyDateParamProvider.class).to(ParamConverterProvider.class).ranked(10);
            }
        });
    }
}

Does not work:

@javax.ws.rs.ApplicationPath("api")
public class ApplicationConfig extends ResourceConfig {
    public ApplicationConfig() {
        register(MyDateParamProvider.class);
    }
}

Extending javax.ws.rs.core.Application and overriding getClasses() does not work either (which means that we must rely on hk2 bindings).

I've tested it with GlassFish 4.1.

While I think that this is still the same bug, I can open a new bug if you want. Unfortunately I don't know how to boostrap the latest version of Jersey with GlassFish, or how to bootstrap a standalone version of Jersey. If you think that this is an upstream GlassFish bug please let me know.

Suggestion: Lower the priority of org.glassfish.jersey.server.internal.inject.ParamConverters.* so that users can bind new ParamConverterProvider for default types without touching hk2.

Comment by jinahya [ 20/Jul/16 ]

I'm facing the same problem with Payara 4.1.1.162.





[JERSEY-3137] Logging Feature duplicates logs Created: 18/Jul/16  Updated: 19/Jul/16  Resolved: 19/Jul/16

Status: Resolved
Project: jersey
Component/s: None
Affects Version/s: 2.23.1
Fix Version/s: 2.24

Type: Bug Priority: Major
Reporter: adrianboimvaser Assignee: Pavel Bucek
Resolution: Works as designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

All requests and responses get logged twice

2016-07-18T18:45:58,527 org.glassfish.jersey.logging.LoggingFeature  INFO - broadcast-vivid_seats-2275-526521-d19951ab-5145-4788-982d-7acae18f3913 : 1 * Sending client request on thread broadcast-vivid_seats-2275-526521-d19951ab-5145-4788-982d-7acae18f3913
1 > GET http://brokers-test.vividseats.com/webservices/listings/v3/get?listingId=1014791183
1 > Accept: application/json

2016-07-18T18:45:58,527 org.glassfish.jersey.logging.LoggingFeature  INFO - broadcast-vivid_seats-2275-526521-d19951ab-5145-4788-982d-7acae18f3913 : 1 * Sending client request on thread broadcast-vivid_seats-2275-526521-d19951ab-5145-4788-982d-7acae18f3913
1 > GET http://brokers-test.vividseats.com/webservices/listings/v3/get?listingId=1014791183
1 > Accept: application/json


 Comments   
Comment by adrianboimvaser [ 18/Jul/16 ]

I meant LoggingFeature.

Comment by Pavel Bucek [ 18/Jul/16 ]

Hi,

thanks for your report. Can you please add reproducer?

I tried to register LoggingFeature into a HelloWorldTest#testConnection and it produced

Jul 19, 2016 12:06:26 AM org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory$GrizzlyTestContainer <init>
INFO: Creating GrizzlyTestContainer configured at the base URI http://localhost:9998/
Jul 19, 2016 12:06:27 AM org.glassfish.grizzly.http.server.NetworkListener start
INFO: Started listener bound to [localhost:9998]
Jul 19, 2016 12:06:27 AM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
log4j:WARN No appenders could be found for logger (org.apache.http.client.protocol.RequestAddCookies).
log4j:WARN Please initialize the log4j system properly.
Jul 19, 2016 12:06:28 AM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 1 * Server has received a request on thread grizzly-http-server-0
1 > GET http://localhost:9998/helloworld
1 > accept: text/plain
1 > accept-encoding: gzip,deflate
1 > connection: Keep-Alive
1 > host: localhost:9998
1 > user-agent: Jersey/2.24-SNAPSHOT (Apache HttpClient 4.5)

Jul 19, 2016 12:06:28 AM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 1 * Server responded with a response on thread grizzly-http-server-0
1 < 200
1 < Content-Type: text/plain
Hello World!

Jul 19, 2016 12:06:28 AM org.glassfish.grizzly.http.server.NetworkListener shutdownNow
INFO: Stopped listener bound to [localhost:9998]

which seems to be OK.

Comment by adrianboimvaser [ 19/Jul/16 ]

Happened with client in a multi-threaded environment. Where can I find HelloWorldTest?

Comment by adrianboimvaser [ 19/Jul/16 ]

Only happened when using org.slf4j.bridge.SLF4JBridgeHandler and installing it using Spring like:

    <bean id="slf4JBridgeHandler" class="org.slf4j.bridge.SLF4JBridgeHandler" init-method="removeHandlersForRootLogger"/>

    <bean class="org.slf4j.bridge.SLF4JBridgeHandler" init-method="install" depends-on="slf4JBridgeHandler"/>

Had to install it from my main method like:

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
Comment by Pavel Bucek [ 19/Jul/16 ]

does the last comment mean that the issue was on your side (config outside of Jersey) and this ticket can be closed?

Comment by adrianboimvaser [ 19/Jul/16 ]

Yes, thank you.





[JERSEY-2506] [jersey-spring3] Calling a Method from a Spring Injected HttpServletRequest causes an IllegalStateException Created: 06/May/14  Updated: 19/Jul/16  Resolved: 19/Jul/16

Status: Resolved
Project: jersey
Component/s: extensions
Affects Version/s: 2.8
Fix Version/s: 2.24, 3.0

Type: Bug Priority: Major
Reporter: tim1973 Assignee: Marek Potociar
Resolution: Fixed Votes: 4
Labels: spring
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Spring 2.8.3.RELEASE


Tags: spring
Sprint: Team Sarracenia

 Description   

Anytime spring injects an HttpServletRequest into a class that is not managed by Jersey (non-resource class), the proxy for the request is injected as expected at startup, but when this any method on request is called, the following exception is thrown:

Caused by: java.lang.IllegalStateException: Current request is not a servlet request
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:279)
at org.springframework.web.context.support.WebApplicationContextUtils.access$300(WebApplicationContextUtils.java:63)
at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:292)
at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:288)
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:304)
at com.sun.proxy.$Proxy48.getAttribute(Unknown Source)

The code in question looks like this:

/**

  • Return the current RequestAttributes instance as ServletRequestAttributes.
  • @see RequestContextHolder#currentRequestAttributes()
    */
    private static ServletRequestAttributes currentRequestAttributes() {
    RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
    if (!(requestAttr instanceof ServletRequestAttributes)) { throw new IllegalStateException("Current request is not a servlet request"); }

    return (ServletRequestAttributes) requestAttr;
    }

It is thrown because the RequestAttributes instance is an instance of JaxrsRequestAttributes.

The case I have is that I'm using Spring's conversion service to convert from JAXB generated objects to domain level objects. I'm injecting an HttpServletRequest into it to get an attribute. The conversion service is the injected into the resource.



 Comments   
Comment by dansiviter [ 21/Sep/15 ]

Basically, it's impossible to inject Servlet artefacts (e.g. HttpServletRequest) into Spring beans due to this using javax.inject.Provider or the Spring ObjectFactoryDelegatingInvocationHandler proxy.

Comment by fejjsong [ 17/Nov/15 ]

This is a bug.
Google Guice can inject HttpServletRequest into beans.But jersey2.0-guice is not released.

Comment by Marek Potociar [ 07/Dec/15 ]

While it seems to be a valid issue, it is not critical to core functionality and we do not plan to dedicate resources to fixing the issue at the moment. In case you feel strongly about the issue, please consider contributing a fix by submitting a Github pull request.





Generated at Mon Jul 25 04:20:55 UTC 2016 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.