Niloy Datta
Niloy Datta

Reputation: 365

Class cast exception in JWT

I am creating a token string using JwtBuilder. But while extracting a value using a key, it is giving ClassCastException. For better understanding code snippet are provided below:

Token creation:

private JwtBuilder getJwtBuilder(
        String jti,
        Long issuedAt,
        Long expiredAt,
        Long businessAccountId,
        Long consumerAccountId,
        String deviceId
) {
    JwtBuilder builder = Jwts.builder();
    builder.setIssuer("SO");
    builder.setSubject(TokenConstant.TOKEN_SUBJECT);
    builder.setId(jti);
    builder.setIssuedAt(new Date(issuedAt));
    builder.setExpiration(new Date(expiredAt));
    builder.claim(TokenConstant.BUSINESS_ACCOUNT_ID, businessAccountId);
    builder.claim(TokenConstant.DEVICE_ID, deviceId);
    builder.signWith(SignatureAlgorithm.HS512, secretKey);
    return builder;
}

Decoding token:

private JsonWebToken decodeToken(String jsonWebToken) {
    try {
        Jws<Claims> map = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jsonWebToken);
        Claims claims = map.getBody();
        return getJsonWebTokenFromClaims(claims);
    } catch (SignatureException | MalformedJwtException e) {
        throw new InvalidTokenException(e.getMessage());
    }
}

private JsonWebToken getJsonWebTokenFromClaims(Claims claims) {
    JsonWebToken token = new JsonWebToken();
    token.jti = claims.getId();
    token.expirationTime = claims.getExpiration().getTime();
    token.issuedAt = claims.getIssuedAt().getTime();
    token.deviceId = (String) claims.get(TokenConstant.DEVICE_ID);
    token.businessAccountId =  (Long) claims.get(TokenConstant.BUSINESS_ACCOUNT_ID);
    return token;
}

Exception:

2018-04-23 10:27:04.476 ERROR b.c.i.s.c.MyExceptionHandler - Application error: {} java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

jwt version:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.6.0</version>
</dependency>

As you can see that my code is getting an error while casting Integer type value to a Long type. I am unable to understand, why Object type is converted to Integer implicitly?

Upvotes: 5

Views: 5027

Answers (2)

Reaz Murshed
Reaz Murshed

Reputation: 24231

I would suggest upgrading the version of your jwt dependency to version 0.9.0.

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
</dependency>

The issue was reported here as an issue in Github which indicates the auto binding to the data type based on smaller values set as a claim. I am copying the exact statement from the issue to elaborate more.

  String claimName = "long"
  Long claimVal = new Long(5)
  String compact = Jwts.builder().setClaims([(claimName): claimVal]).compact();
  Claims claims = Jwts.parser().parse(compact).body as Claims
  // `claims.get` throws `RequiredTypeException`
  assert claims.get(claimName, Long) == claimVal

Here, Jackson finds that a 5 is small enough to fit in the Integer and so unmarshalls into it, instead of expected Long.

What makes matters worse is that when a value is large enough (≥ 2^31), Jackson will switch to Long and so code that naively always get()-s Integer will stop working:

However, the issue has been fixed in this pull request and is available in the newer released version of the jwt library.

After updating the library you can get the proper value without having a RequiredTypeException using the following code.

// businessAccountId is declared as Long I guess
token.businessAccountId = claims.get(TokenConstant.BUSINESS_ACCOUNT_ID, Long.class);

Hope that fixes your problem.

Upvotes: 7

Varun Srivastawa
Varun Srivastawa

Reputation: 72

Token creation file 3rd line from bottom you are doing ".longvalue()". I think you should try to change type of field "business AccountId"to Long

Upvotes: 0

Related Questions