3

I am developing an application targeting a Java EE 8 application server (JBoss/Wildfly).

However, one of the dependencies (elasticsearch api) is already using jakarta.json.* classes which results in a ClassCastException at runtime:

java.lang.ClassCastException: org.glassfish.json.JsonProviderImpl cannot be cast to jakarta.json.spi.JsonProvider

That is because the org.classfish.json.JsonProviderImpl in my classpath (org.classfish:javax.json:1.1.4) is still using javax.json classes.

However, as both org.glassfish:jakarta.json and org.classfish:javax.json define the same class org.classfish.json.JsonProviderImpl (one using the javax.json.* classes and one using the jakarta.json.* classes...), I am unable to simply include both maven artifacts.

The implementation of JsonProviderImpl (in both artifacts!) basically returns the following by default:

return Class.forName("org.glassfish.json.JsonProviderImpl");

When both org.glassfish:jakarta.json and org.classfish:javax.json are on the classpath, this will cause issue for any of the implementations which will get the JsonProviderImpl from the other package.

What can I do to resolve this?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Matthias
  • 12,053
  • 4
  • 49
  • 91
  • I have created https://github.com/elastic/elasticsearch-java/issues/55 to ask specifically about the situation with Elasticsearch. However, the general issue remains whether javax.json.* and jakarta,json.* can both be used within the same application. – Matthias Dec 10 '21 at 10:23
  • 2
    Can't you just pick an Elasticsearch version suitable for your environment? – BalusC Dec 10 '21 at 11:42
  • @BalusC: Elasticsearch itself is already running using Java 11 and will likely be kept current. As the "old" Java REST Client is being deprecated, I would like to use the "new" Java Client for Elasticsearch from my Java application - however, Wildfly for Jakarta EE 9 is still in preview stage, so I have to use Java EE 8 for now. – Matthias Dec 10 '21 at 11:51

2 Answers2

2

For reference: This has been fixed by the Elastic team: They have switched from the Glassfish implementation

api("org.glassfish", "jakarta.json", "2.0.1")

to Eclipse Parsson:

api("jakarta.json:jakarta.json-api:2.0.1")
api("org.eclipse.parsson:parsson:1.0.0")
Matthias
  • 12,053
  • 4
  • 49
  • 91
  • I'm happy for a WORKAROUND, but this is clearly a workaround. The problem is, why it happens, that I add glassfish's implementation, which is implementing the proper interface and the ServiceLoader doesn't find it on the factory method? Most likely glassfish's package is missing something. I ran into this problem but not with colliding class names, but simply updating myself on jakarta api and replacing my javax glassfish json to jakarta glassfish json – newhouse Aug 02 '23 at 10:49
1

One workaround seems to be to use the maven shade plugin to basically "rename" the package org.glassfish.json in the "new" org.glassfish:jakarta.json to jakarta.org.glassfish.json:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <filters>
          <filter>
            <artifact>org.glassfish:jakarta.json</artifact>
            <includes>
              <include>org/glassfish/json/**</include>
            </includes>
          </filter>
        </filters>
        <artifactSet>
          <includes>
            <include>org.glassfish:jakarta.json</include>
          </includes>
        </artifactSet>
        <relocations>
          <relocation>
            <pattern>org.glassfish.json</pattern>
            <shadedPattern>jakarta.org.glassfish.json</shadedPattern>
          </relocation>
        </relocations>
      </configuration>
    </plugin>
  </plugins>
</build>

Then, one can create the file src/main/resources/META-INF/services/jakarta.json.spi.JsonProvider with the following content:

jakarta.org.glassfish.json.JsonProviderImpl

This will tell the implementation of jakarta.json.spi.JsonProvider to use the shaded version of the JsonProviderImpl (from the org.glassfish:jakarta.json artifact - which uses the jakarta.json.* classes) instead of the JsonProviderImpl (with the same name from org.glassfish:javax.json).

Matthias
  • 12,053
  • 4
  • 49
  • 91