Jersey Inject Weld managed bean into ConstraintVal

2019-05-14 07:16发布

问题:

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

回答1:

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();


回答2:

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.