简体   繁体   中英

Jersey - How to use @Context annotation outside of a servlet?

I am trying to set up a Jersey ClientResponseFilter. It is working fine, but I want to deserialize my request parameters into a String so I can write helpful messages into a log file containing the actual data.

I was thinking about using MessageBodyWorkers for this. As this link below says: "In case you need to directly work with JAX-RS entity providers, for example to serialize an entity in your resource method, filter or in a composite entity provider, you would need to perform quite a lot of steps."

Source: 7.4. Jersey MessageBodyWorkers API

This is exactly what I want to prevent.

So I was thinking about injecting the messagebodyworkers into my filter like this:

package somepackage.client.response;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;

import org.glassfish.jersey.message.MessageBodyWorkers;
import org.slf4j.Logger;

@Provider
public class ResponseFilter implements ClientResponseFilter {

    // TODO: these workers are not injected
    @Context
    private MessageBodyWorkers workers;
    private final Logger logger;

    public ResponseFilter(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext)
            throws IOException {
        if (responseValid(responseContext)) {
            return;
        }
        logger.error("Error", "Some param");
    }

    private boolean responseValid(ClientResponseContext responseContext) {
        if (responseContext.getStatus() == HttpServletResponse.SC_OK) {
            return true;
        }
        return false;
    }

}

But the reference is always null and remains null. Note that this filter is running in a standalone application, no servlet container is available.

Why isn't the annotation working in this case? How can I make it work? Or if making this approach to work is impossible, how can I work around this?

Any suggestions?

OK. Here is the workaround solution for the problem above: we should use @Inject and the HK2 Dependency Injection Kernel

HK2 Dependency Injection Kernel Link

First we need to make some changes to the filter:

package somepackage.client.response;

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;

import org.glassfish.jersey.message.MessageBodyWorkers;
import org.slf4j.Logger;

public class ResponseFilter implements ClientResponseFilter {

    @Inject
    private MessageBodyWorkers workers;
    private Logger logger;

    @Override
    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext)
            throws IOException {
        if (responseValid(responseContext)) {
            return;
        }
        logger.error("Error", "Some param");
    }

    private boolean responseValid(ClientResponseContext responseContext) {
        if (responseContext.getStatus() == HttpServletResponse.SC_OK) {
            return true;
        }
        return false;
    }

    public void setLogger(Logger logger) {
        this.logger = logger;
    }

}

As you can see the constructor changed, the class uses the default constructor, and the annotation changed to @Inject. Be aware that there are two @Inject annotations with the same name. Make sure you use: javax.inject.Inject.

Then we need to implement org.glassfish.hk2.utilities.binding.AbstractBinder:

package somepackage.client;

import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.message.MessageBodyWorkers;
import org.glassfish.jersey.message.internal.MessageBodyFactory;

public class Binder extends AbstractBinder {

    @Override
    protected void configure() {
        bind(MessageBodyFactory.class).to(MessageBodyWorkers.class);
    }

}

And finally we should register the filter and our binder in the client:

...
        client.register(ResponseFilter.class);
        client.register(new SitemapBinder());
...

Then the worker is going to be injected fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM