eclipse-ee4j / jersey

Eclipse Jersey Project - Read our Wiki:

Home Page:https://github.com/eclipse-ee4j/jersey/wiki

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Jersey multiple provider instances for multiple provider interfaces; again?

Conrad-T-Pino opened this issue · comments

I'm suggesting not fixed in Jersey 2.35 nor 2.44. I'm logging in no argument constructor and see four (4) log entries; one for each implemented Contract.class for the first request but not thereafter.

Ideally I wanted singleton state as class field in singleton instance. Logs suggest I must use static field to circumvent multiple instances.

public class ClientCapture implements 
	ClientRequestFilter, ClientResponseFilter, ReaderInterceptor, WriterInterceptor {
	public ClientCapture() {
		super();
		logger.info("ClientCapture()");
	}
	...
}
25-Aug-2024 15:02:24.978 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
25-Aug-2024 15:02:24.978 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
25-Aug-2024 15:02:24.982 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
25-Aug-2024 15:02:24.983 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
25-Aug-2024 15:02:25.078 INFO [pool-6-thread-1] tmms.rest.ClientCapture.filter (ClientRequestContext)
25-Aug-2024 15:02:25.090 INFO [pool-6-thread-1] tmms.rest.ClientCapture.aroundWriteTo (WriterInterceptorContext)
25-Aug-2024 15:02:25.785 INFO [pool-6-thread-1] tmms.rest.ClientCapture.filter (ClientRequestContext, ClientResponseContext)
25-Aug-2024 15:02:25.790 INFO [pool-6-thread-1] tmms.rest.ClientCapture.aroundReadFrom (ReaderInterceptorContext)

Originally posted by @Conrad-T-Pino in #3888 (comment) and #3796

@Conrad-T-Pino What Injection module do you use? jersey-cdi2-se or jersey-hk2?

Again, context matters:

  • Container: time constraints require using existing Tomcat 9 installation
  • Specification: Servlet 4.0, JSP 2.3, EL 3.0, Java EE 8, CDI 2.0, JPA 2.2, JSF 2.3
  • User: experienced Tomcat webapp developer doing first JAX-RS (Jersey) application
  • Application: reverse proxy complex rate limiting Telnyx JSON API into trivial GET API
  • Telnyx: client Java SDK doesn't expose response headers but does expose JAX-RS Client

Objective is capture Telnyx client response headers:

final com.telnyx.sdk.ApiClient apiClient = com.telnyx.sdk.Configuration.getDefaultApiClient();
final javax.ws.rs.client.Client httpClient = apiClient.getHttpClient();
httpClient.register(tmms.rest.ClientCapture.class);

@jansupol ClientCapture class is NOT annotated and ignored by org.glassfish.jersey.servlet.ServletContainer

@jansupol jersey-hk2 is in play. Redacted pom.xml follows:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>tmms.rest</groupId>
  <artifactId>tmms</artifactId>
  <version>0.0.0-dev</version>
  <packaging>war</packaging>

  <name>tmms</name>

  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <telnyx.version>3.6.1</telnyx.version>
    <jersey.version>2.44</jersey.version>
    <webapp.lib>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</webapp.lib>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.glassfish.jersey</groupId>
        <artifactId>jersey-bom</artifactId>
        <version>${jersey.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>4.0.4</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.containers</groupId>
      <artifactId>jersey-container-servlet</artifactId>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.inject</groupId>
      <artifactId>jersey-hk2</artifactId>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.ext</groupId>
      <artifactId>jersey-bean-validation</artifactId>
    </dependency>
    <dependency>
      <groupId>com.telnyx.sdk</groupId>
      <artifactId>telnyx</artifactId>
      <version>${telnyx.version}</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>tmms</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

To verify container provider behavior I restacked my classes:

//@Provider
public class Interceptors implements ReaderInterceptor, WriterInterceptor {
	public Interceptors() {
		super();
		logger.info("Interceptors()");
	}
	...
}
//@Provider
public class ClientCapture extends Interceptors implements ClientRequestFilter, ClientResponseFilter {
	public ClientCapture() {
		super();
		logger.info("ClientCapture()");
	}
	...
}
@Provider
public class ContainerCapture extends Interceptors implements ContainerRequestFilter, ContainerResponseFilter {
	public ContainerCapture() {
		super();
		logger.info("ContainerCapture()");
	}
	...
}

The client constructors log as expected:

26-Aug-2024 14:19:37.349 INFO [pool-6-thread-1] tmms.rest.Interceptors.<init> Interceptors()
26-Aug-2024 14:19:37.349 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
26-Aug-2024 14:19:37.350 INFO [pool-6-thread-1] tmms.rest.Interceptors.<init> Interceptors()
26-Aug-2024 14:19:37.350 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
26-Aug-2024 14:19:37.354 INFO [pool-6-thread-1] tmms.rest.Interceptors.<init> Interceptors()
26-Aug-2024 14:19:37.354 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
26-Aug-2024 14:19:37.355 INFO [pool-6-thread-1] tmms.rest.Interceptors.<init> Interceptors()
26-Aug-2024 14:19:37.355 INFO [pool-6-thread-1] tmms.rest.ClientCapture.<init> ClientCapture()
26-Aug-2024 14:19:37.449 INFO [pool-6-thread-1] tmms.rest.ClientCapture.filter (ClientRequestContext):
26-Aug-2024 14:19:37.462 INFO [pool-6-thread-1] tmms.rest.Interceptors.aroundWriteTo (WriterInterceptorContext):
26-Aug-2024 14:19:38.339 INFO [pool-6-thread-1] tmms.rest.ClientCapture.filter (ClientRequestContext, ClientResponseContext):
26-Aug-2024 14:19:38.344 INFO [pool-6-thread-1] tmms.rest.Interceptors.aroundReadFrom (ReaderInterceptorContext):

The container constructors are silent in all cases:

26-Aug-2024 14:51:04.756 INFO [catalina-exec-1] tmms.rest.ContainerCapture.filter (ContainerRequestContext):
26-Aug-2024 14:51:05.051 INFO [catalina-exec-1] tmms.rest.ContainerCapture.filter (ContainerRequestContext, ContainerResponseContext):
26-Aug-2024 14:51:05.057 INFO [catalina-exec-1] tmms.rest.Interceptors.aroundWriteTo (WriterInterceptorContext):
26-Aug-2024 14:51:06.390 INFO [catalina-exec-4] tmms.rest.ContainerCapture.filter (ContainerRequestContext):
26-Aug-2024 14:51:06.392 INFO [catalina-exec-4] tmms.rest.Interceptors.aroundReadFrom (ReaderInterceptorContext):
26-Aug-2024 14:51:07.020 INFO [catalina-exec-2] tmms.rest.ContainerCapture.filter (ContainerRequestContext):
26-Aug-2024 14:51:07.022 INFO [catalina-exec-2] tmms.rest.Interceptors.aroundReadFrom (ReaderInterceptorContext):
  • Thread 1 is request from our test client.
  • Threads 4 & 2 are Telnyx webhook updates.