Search code examples
javajunitjwtjjwt

Getting java.lang.NoSuchMethodException: io.jsonwebtoken.impl.crypto.MacProvider.generateKey only in case of jUnits


I have recently started getting following exception, only when junits are being run. In normal flow, the method runs fine. (In fact even the jUnits used to work fine till some time back)

java.lang.NoSuchMethodException: io.jsonwebtoken.impl.crypto.MacProvider.generateKey(io.jsonwebtoken.SignatureAlgorithm)

Following is the method:

public static String generateDummyJWT(String userName)
{
    return Jwts.builder().claim("user_name", StringUtils.defaultString(userName)).setAudience("client1").signWith(Keys.secretKeyFor(SignatureAlgorithm.HS384)).compact();   
}

And jjwt versions:

enter image description here

Following is the complete stack trace:

Caused by: java.lang.IllegalStateException: Unable to invoke class method io.jsonwebtoken.impl.crypto.MacProvider#generateKey. Ensure the necessary implementation is in the runtime classpath. at io.jsonwebtoken.lang.Classes.invokeStatic(Classes.java:202) at io.jsonwebtoken.security.Keys.secretKeyFor(Keys.java:121) at com.random.util.ServiceSpecificUtil.generateDummyJWT(ServiceSpecificUtil.java:143) at com.random.util.ServiceConstants.(ServiceConstants.java:203) at com.random.MyClass.isUserBranch(MyClass.java:67) at com.random.MyClass.validName(MyClass.java:93) at com.random.MyClass.preConditionCheck(MyClass.java:82) at com.random.MyClass.get(MyClass.java:46) at com.random.MyClass2.evaluateExpression(MyClass2.java:218) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl$1.invoke(MockitoMethodInvocationControl.java:243) at org.mockito.internal.invocation.realmethod.CleanTraceRealMethod.invoke(CleanTraceRealMethod.java:30) at org.mockito.internal.invocation.InvocationImpl.callRealMethod(InvocationImpl.java:112) at org.mockito.internal.stubbing.answers.CallsRealMethods.answer(CallsRealMethods.java:41) at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:93) at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:266) at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:192) at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:132) at org.powermock.core.MockGateway.methodCall(MockGateway.java:63) at com.random.MyClass2.evaluateExpression(MyClass2.java) at com.random.MyClass2.isPermitted(MyClass2.java:107) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl$1.invoke(MockitoMethodInvocationControl.java:243) at org.mockito.internal.invocation.realmethod.CleanTraceRealMethod.invoke(CleanTraceRealMethod.java:30) at org.mockito.internal.invocation.InvocationImpl.callRealMethod(InvocationImpl.java:112) at org.mockito.internal.stubbing.answers.CallsRealMethods.answer(CallsRealMethods.java:41) at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:93) at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:266) at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:192) ... 32 more Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at io.jsonwebtoken.lang.Classes.invokeStatic(Classes.java:198) ... 66 more Caused by: java.lang.IllegalStateException: The HmacSHA384 algorithm is not available. This should never happen on JDK 7 or later - please report this to the JJWT developers. at io.jsonwebtoken.impl.crypto.MacProvider.generateKey(MacProvider.java:94) at io.jsonwebtoken.impl.crypto.MacProvider.generateKey(MacProvider.java:63) ... 71 more Caused by: java.security.NoSuchAlgorithmException: HmacSHA384 KeyGenerator not available at javax.crypto.KeyGenerator.(KeyGenerator.java:169) at javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:223) at io.jsonwebtoken.impl.crypto.MacProvider.generateKey(MacProvider.java:92) ... 72 more


Solution

  • I was able to resolve my problem.

    Someone in the team had added the call to above function while initializing a static final variable like this:

    public static String TOKEN_GUEST = ServiceSpecificUtil.generateDummyJWT(USERNAME);
    

    Now, it seems that access to the java.security packges generally does not work well with PowerMock due to heavy use of reflections & byte code manipulations:

    Although I had referred this SO post and tried the suggested solution of using @PowerMockIgnore like:

    @PowerMockIgnore({"org.apache.http.conn.ssl.*", "javax.net.ssl.*" , "javax.crypto.*"})
    

    and that might be helpful in preventing errors when above function was called from another function. But it was not preventing errors in static variable initialization.

    public static String TOKEN_GUEST = ServiceSpecificUtil.generateDummyJWT(USERNAME);
    

    I will update this post when I dig deeper as to why the error was coming only in case of static variable initialization and not when ServiceSpecificUtil.generateDummyJWT(USERNAME) was being called from another function.