swagger-api / swagger-api/swagger-codegen

Problem with Context injection in jersey 2

Open
#7,122 5 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Client: Java Issue: Bug
Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

The issue that I am hitting is that in the environment that I am using the injection with the constructor that is annotated with @Context does not seem to be working properly...

public class PodManagersApi  {
   private final PodManagersApiService delegate;

   public PodManagersApi(@Context ServletConfig servletContext) {
      PodManagersApiService delegate = null;

The underlying problem is captured in the posting below ...

https://stackoverflow.com/questions/37683765/jersey-constructor-injection-with-context-not-working

Swagger-codegen version

2.22.3

It originated with the change at..

https://github.com/swagger-api/swagger-codegen/pull/5662

Swagger declaration file content or url

`

Command line used for generation
    lang = "jaxrs"
    library = "jersey2"
....
     doLast {

                def swaggerIn =
                        new File("${project.projectDir}/${project.swagger.swaggersDir}/${project.swagger.swaggerFile}")
                def swaggerOut =
                        new File("${project.buildDir}/${project.swagger.outputLocation}")
                swaggerOut.mkdirs()

                def config = new CodegenConfigurator()
                config.setInputSpec(swaggerIn.path)
                config.setOutputDir(swaggerOut.path)
                config.setLang(project.swagger.lang.toString())
                config.setLibrary(project.swagger.library.toString())
                config.setAdditionalProperties([
                        'sourceFolder'   : 'src/main/java'.toString(),
                        'groupId'        : (project.swagger.swaggerGroupId ?: project.group).toString(),
                        'artifactId'     : (project.swagger.swaggerArtifactId ?: project.name).toString(),
                        'artifactVersion': (project.swagger.swaggerArtifactVersion ?: project.version).toString(),
                        'invokerPackage' : (project.swagger.packageName + '.client').toString(),
                        'modelPackage'   : (project.swagger.packageName + '.model').toString(),
                        'apiPackage'     : (project.swagger.packageName + '.api').toString()//,
                        // TODO: broken in 2.2.2 of code gen
                        //'dateLibrary'    : 'java8'.toString()
                ])
                new DefaultGenerator().opts(config.toClientOptInput()).generate()
Steps to reproduce

Create a war from the above and deploy it. curl the target and you will get an exception of the kind..

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 1
org.jboss.weld.exceptions.CreationException: WELD-001530: Cannot produce an instance of class com.oracle.fa.lcm.rest.fasaasmgr.api.PodManagersApi.
	at org.jboss.weld.injection.producer.NonProducibleInjectionTarget.produce(NonProducibleInjectionTarget.java:79)
	at org.glassfish.jersey.ext.cdi1x.internal.AbstractCdiBeanHk2Factory$2.getInstance(AbstractCdiBeanHk2Factory.java:139)
	at org.glassfish.jersey.ext.cdi1x.internal.AbstractCdiBeanHk2Factory._provide(AbstractCdiBeanHk2Factory.java:91)
	at org.glassfish.jersey.ext.cdi1x.internal.GenericCdiBeanHk2Factory.provide(GenericCdiBeanHk2Factory.java:63)
	at org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:153)
	at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:487)
	at org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:70)
	at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2022)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:774)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:737)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:707)
	at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:172)
	at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:284)
	at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:74)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:109)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:112)
	at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:92)
	at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:61)
	at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
	at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:318)`
Related issues/PRs
Suggest a fix/enhancement

The following changes seemed to resolve the issue when made manually...

@Context
private ServletConfig servletContext;

@PostConstruct
private void initDelegate() {


  java.util.logging.Logger.getGlobal().severe("POSTCONSTRUCT!!!!!!!!!");
  FooManagersApiService delegate = null;

  if (servletContext != null) {
    String implClass = servletContext.getInitParameter("FooManagersApi.implementation");
    if (implClass != null && !"".equals(implClass.trim())) {
      try {
        delegate = (FooManagersApiService) Class.forName(implClass).newInstance();
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
  }

  if (delegate == null) {
    delegate = FooManagersApiServiceFactory.getFooManagersApi();
  }

  this.delegate = delegate;

}

Alternatively, I was wondering if it might make sense to just use direct injection as an option..
As in....

public class PodManagersApi  {
   @Inject
   private final PodManagersApiService delegate;

Then adding...

@javax.annotation.Generated(value = "io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2017-12-04T17:38:39.050-05:00")
@Contract
public abstract class FooManagersApiService {
    public abstract Response getAllFooManagers(SecurityContext securityContext) throws NotFoundException;
}

and...

@javax.annotation.Generated(value = "io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2017-12-04T17:38:39.050-05:00")
@Service
public class FooManagersApiServiceImpl extends FooManagersApiService {

    @Override
    public Response getAllFooManagers(SecurityContext securityContext) throws NotFoundException {

This would make it really easy to override or use qualifiers without having to modify any source code or even descriptors..

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the failure using the shown jaxrs and jersey2 CodegenConfigurator settings, then inspect the generated PodManagersApi constructor and the JavaJerseyServerCodegen output. Compare the failing constructor-based @Context injection with the field-injection and @PostConstruct example; done means the generated WAR deploys and the request no longer produces the Weld CreationException.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.