Antares42
Antares42

Reputation: 1436

Can I create a request-scoped object and access it from anywhere, and avoid passing it around as a parameter in JAX-RS?

Say I have a web service / a REST resource that is called with some HTTP header parameters. The resource method builds a complex data object (currently a POJO) and eventually returns it to the client (via Gson as JSON, but that doesn't matter).

So I have this call hierarchy:

@Path(foo) ProjectResource @GET getProject()
-> new Project()
-> new List<Participant> which contains lots of new Participant()s
-> new Affiliation()

If I want the Affiliation object to be e.g. populated in English or German depending on a header parameter, I have to pass that as a parameter down the chain. I want to avoid having to do that. Maybe this is just fundamentally impossible, but it feels so wrong. All these objects only live inside the request, so wouldn't it be convenient to be able to access information tied to the request from anywhere?

I was hoping I could e.g. define a CDI @RequestScoped object that initialized itself (or gets populated by some WebFilter) and that I can then inject where I might need it.

But obviously that doesn't work from inside the POJOs, and I also had trouble getting hold of the headers from inside the request-scoped object.

I've read many SO questions/answers about EJBs and JAX-RS Context and CDI but I can't wrap my head around it.

Am I expecting too much? Is passing down the parameter really the preferred option?

Upvotes: 1

Views: 2950

Answers (1)

cassiomolin
cassiomolin

Reputation: 131067

If I understand what you need, you can try the following (just wrote this solution from the top of my head, but it should work):

Defining a class to store the data you need

Define a class annotated with @RequestScoped which will store the data you need:

@RequestScoped
public class RequestMetadata {

    private Locale language;

    // Default constructor, getters and setters ommited
}

Ensure you are using the @RequestScoped annotation from the javax.enterprise.context package.

Creating a request filter

Create a ContainerRequestFilter to populate the RequestMetadata:

@Provider
@PreMatching
public class RequestMetadataFilter implements ContainerRequestFilter {

    @Inject
    private RequestMetadata requestMetadata;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        requestMetadata.setLanguage(requestContext.getLanguage());
    }
}

Performing the injection

And then you can finally perform the injection of the RequestMetadata using @Inject:

@Stateless
public class Foo {

    @Inject
    private RequestMetadata requestMetadata;

    ...
}

Please, be aware that anywhere is too broad: The injection will work into beans managed by the container, such as servlets, JAX-RS classes, EJB and CDI beans, for example.

You won't be able to perform injections into beans created by yourself neither into JPA entities.

Upvotes: 6

Related Questions