Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

graal support? #637

Open
janjangao opened this issue Dec 28, 2020 · 21 comments
Open

graal support? #637

janjangao opened this issue Dec 28, 2020 · 21 comments
Labels
enhancement help-wanted If you're looking to help the project, start with these!

Comments

@janjangao
Copy link

I use jjwt generate token for my micronaut app,I use graalvm build native-image, when generate token, I get this error:

io.jsonwebtoken.lang.UnknownClassException: Unable to load class named [io.jsonwebtoken.impl.DefaultJwtBuilder] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found. Have you remembered to include the jjwt-impl.jar in your runtime classpath?

I already setting jjwt-impl.jar in build.gradle, but because of native-image has limitation with reflection, so dynamic class loading can not work, I follow the graal manual add reflection-config.json in META-INF and its working!

[ { "name" : "io.jsonwebtoken.impl.DefaultJwtBuilder", "allDeclaredFields" : true, "allPublicMethods" : true, "allDeclaredConstructors" : true } ]

so can we just put the graal config in jjwt-impl.jar to support graal native-image?

@lhazlewood
Copy link
Contributor

We'd welcome a pull request for this, but it's low priority for the core JJWT team until 1.0 is released.

@stale stale bot added the stale Stale issues pending deletion due to inactivity label Jun 2, 2021
@bdemers bdemers removed the stale Stale issues pending deletion due to inactivity label Jun 2, 2021
@jwtk jwtk deleted a comment from stale bot Jun 2, 2021
@stale
Copy link

stale bot commented Aug 4, 2021

This issue has been automatically marked as stale due to inactivity for 60 or more days. It will be closed in 7 days if no further activity occurs.

@stale stale bot added the stale Stale issues pending deletion due to inactivity label Aug 4, 2021
@bdemers bdemers removed the stale Stale issues pending deletion due to inactivity label Aug 5, 2021
@MarkusKramer
Copy link

MarkusKramer commented Sep 3, 2021

Only adding DefaultJwtBuilder will not be sufficient if you want to parse a JWT. I've got jjwt working in a Graal native image build now. Parsing a JWT can be done like this:

            DefaultJwtParserBuilder()
                .deserializeJsonWith(JacksonDeserializer())
                .build()
                .parse...

You'll also need some config files to get compression to work - which unfortunately you currently can't get rid of as it's always getting statically initialized even when not needed.

META-INF/native-image/someprojectname/resource-config.json

{
  "resources": {
    "includes": [
      {
        "pattern": "META-INF/services/io.jsonwebtoken.CompressionCodec"
      }
    ]
  }
}

META-INF/native-image/someprojectname/reflect-config.json

[
  {
    "name": "io.jsonwebtoken.impl.compression.GzipCompressionCodec",
    "methods": [
      {
        "name": "<init>",
        "parameterTypes": []
      }
    ]
  },
  {
    "name": "io.jsonwebtoken.impl.compression.DeflateCompressionCodec",
    "methods": [
      {
        "name": "<init>",
        "parameterTypes": []
      }
    ]
  }
]

These files could also be bundled with the jjwt artifact and then it would work more out of the box. Alternatively, it would be great if jjwt would use less dynamic classloading logic.

@lhazlewood
Copy link
Contributor

Thanks for the update @MarkusKramer . Is it possible to declare DefaultJwtParserBuilder and DefaultJwtBuilder in resource-config.json as well, and then have it work 'out of the box' without having to use jjwt-impl in compile-scope?

Nothing in the impl module is guaranteed for backwards compatibility. If you directly use its classes as above, breaking changes could occur on future upgrades.

@MarkusKramer
Copy link

Yes, you can use Jwts.parserBuilder() if you add to reflect-config.json

  {
    "name": "io.jsonwebtoken.impl.DefaultJwtParserBuilder",
    "methods": [
      {
        "name": "<init>",
        "parameterTypes": []
      }
    ]
  },

Just tested with Graal. And similar for the builder and other classes.

When including theses configs in jjwt-impl it should work out of the box.
However... one key benefit of Graal is to get rid of unneeded code, and we're sort of preventing it this way. It would be better to have less reflection in jjwt, by Jwts doing normal class initialization that can be statically analyzed by tools. And DefaultJwtParserBuilder not initializing DefaultCompressionCodecResolver unless actually needed.

@lhazlewood
Copy link
Contributor

lhazlewood commented Sep 6, 2021

A CompressionCodecResolver is always needed in case a zip header is encountered, but I understand your point around reflection.

We have discussed at times moving the impl package and its sub-packages into a single .jar and changing everything in there to package protected to prevent people from depending on those classes, but there needs to be some significant analysis to ensure nothing can 'leak' unexpectedly. It'll be a decent amount of work.

A reflect-config.json might be a better/faster stop-gap in the meantime however.

@stale
Copy link

stale bot commented Apr 16, 2022

This issue has been automatically marked as stale due to inactivity for 60 or more days. It will be closed in 7 days if no further activity occurs.

@stale stale bot added the stale Stale issues pending deletion due to inactivity label Apr 16, 2022
@lhazlewood
Copy link
Contributor

Looks like significant work to support something like this will have to wait until after 1.0 - highest priority is to get JWE released.

@stale stale bot removed the stale Stale issues pending deletion due to inactivity label Apr 18, 2022
@lhazlewood
Copy link
Contributor

(at least unless someone submits a PR that can facilitate this for the current module structure)

@lhazlewood lhazlewood added help-wanted If you're looking to help the project, start with these! enhancement labels Apr 20, 2022
@linghengqian
Copy link

  • Considering that the 1.0 version involved in this issue is likely to be far away from us, I suggest closing this issue.

  • A more reasonable move is to submit the corresponding GraalVM metadata in Oracle's https://github.com/oracle/graalvm-reachability-metadata repository. This will help deal with the problem right away.

@lhazlewood
Copy link
Contributor

@linghengqian thanks for the comment and insight! I think we could leave this open just to ensure we can track it until after the 1.0 release. JJWT's jwe work is mostly finished (mostly working on documentation now), and given the additions and package changes, I agree it doesn't make as much sense to work on this ticket until that is released. At least that way we can have a stable package structure to use to identify any GraalVM-related package metadata.

There will be final API changes after the jwe merge, but before the 1.0 release - mostly dropping or adding certain things to ensure best use of Java 8 APIs (functions, etc). But also perhaps some package changes due to the way the JDK Module System works (api vs impl packages). Then once 1.0 is done, any package-related metadata would make sense since the package structure should be more than stable at that point.

I do agree that, if someone wants this now, adding a PR to the https://github.com/oracle/graalvm-reachability-metadata repository would be the way to go, and then issue another PR after the JJWT 1.0 release.

@linghengqian
Copy link

linghengqian commented Nov 17, 2022

@Haarolean

This comment was marked as outdated.

@akaiser
Copy link

akaiser commented Dec 3, 2023

Hey! Worked fine with 0.11.5 but to be broken/unsupported since 0.12.x again.

Caused by: io.jsonwebtoken.lang.UnknownClassException: Unable to load class named [io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms] from the thread context, current, or system/application ClassLoaders.  All heuristics have been exhausted.  Class could not be found.  Have you remembered to include the jjwt-impl.jar in your runtime classpath?
	at io.jsonwebtoken.lang.Classes.forName(Classes.java:90) ~[na:na]
	at io.jsonwebtoken.lang.Classes.newInstance(Classes.java:173) ~[na:na]
	at io.jsonwebtoken.Jwts$SIG.<clinit>(Jwts.java:174) ~[na:na]

@linghengqian any chance you would want to make this happen again? 🙏

@linghengqian
Copy link

Hey! Worked fine with 0.11.5 but to be broken/unsupported since 0.12.x again.

Caused by: io.jsonwebtoken.lang.UnknownClassException: Unable to load class named [io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms] from the thread context, current, or system/application ClassLoaders.  All heuristics have been exhausted.  Class could not be found.  Have you remembered to include the jjwt-impl.jar in your runtime classpath?
	at io.jsonwebtoken.lang.Classes.forName(Classes.java:90) ~[na:na]
	at io.jsonwebtoken.lang.Classes.newInstance(Classes.java:173) ~[na:na]
	at io.jsonwebtoken.Jwts$SIG.<clinit>(Jwts.java:174) ~[na:na]

@linghengqian any chance you would want to make this happen again? 🙏

@RMCampos
Copy link

Hello. I'm facing this issue with JJWT 0.12.6. This is my first time working with GraalVM and reachability-metadata. Could someone point me in the right direction, on how to modify my project in order to make it work? Thanks in advance.

@RMCampos
Copy link

I've found a way of make it work: You can add the classes you need into your @RegisterReflectionForBinding, like this:

create a file named CloudNativeConfig.java for example, and put this:

import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.context.annotation.Configuration;

@Configuration
@RegisterReflectionForBinding({
  io.jsonwebtoken.Claims.class,
  io.jsonwebtoken.Jwts.class,
  io.jsonwebtoken.Jwts.SIG.class,
  io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms.class,
  io.jsonwebtoken.impl.security.StandardKeyOperations.class,
  /* ... more classes... */
})
public class CloudNativeConfig {}

This worked for me with Java version "17.0.9" 2023-10-17 LTS.

@akaiser
Copy link

akaiser commented Oct 4, 2024

@RMCampos confirming, works well on GraalVM 21.0.4+8.

@TuTrinh-dev
Copy link

TuTrinh-dev commented Nov 21, 2024

I am using version 0.12.6, and here’s how I resolved this issue.

@RegisterReflectionForBinding({
        io.jsonwebtoken.impl.DefaultJwtParser.class,
        io.jsonwebtoken.impl.DefaultClaimsBuilder.class,
        io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms.class,
        io.jsonwebtoken.impl.security.StandardKeyOperations.class,
        io.jsonwebtoken.security.SignatureAlgorithm.class,
        io.jsonwebtoken.impl.security.StandardEncryptionAlgorithms.class,
        io.jsonwebtoken.impl.security.StandardKeyAlgorithms.class,
        io.jsonwebtoken.impl.io.StandardCompressionAlgorithms.class
})

@demtnt
Copy link

demtnt commented Nov 21, 2024

And my kotlin + spring configuration:

@RegisterReflectionForBinding(classes = [
KeysBridge::class, 
StandardEncryptionAlgorithms::class, 
StandardKeyAlgorithms::class, 
StandardSecureDigestAlgorithms::class, 
StandardCompressionAlgorithms::class,
DefaultJwtHeaderBuilder::class, 
DefaultClaimsBuilder::class, 
DefaultJwtBuilder::class, 
DefaultJwtParserBuilder::class, 
StandardKeyOperations::class, 
DefaultKeyOperationBuilder::class,
DefaultKeyOperationPolicyBuilder::class, 
DefaultDynamicJwkBuilder::class, 
DefaultJwkParserBuilder::class, 
DefaultJwkSetBuilder::class, 
DefaultJwkSetParserBuilder::class, JwksBridge::class])
@Configuration
class NativeConf {
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement help-wanted If you're looking to help the project, start with these!
Projects
None yet
Development

No branches or pull requests

10 participants