jjwt
jjwt copied to clipboard
Can't use setHeader(Header) because ambigous method call
Header is both a Header and a Map so this won't work:
Header header = new DefaultHeader();
String payloadWithoutPartner1 = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS256, key)
.setHeader(header)
.compact();
Ambiguous method call. Both setHeader (Header) in JwtBuilder and setHeader(Map<String, Object>) in JwtBuilder match
I don't understand the issue - this is standard Java method overloading, no? Can you please clarify the problem?
Ah, don't instantiate DefaultHeader. Use Jwts.header() ?
Ordinarily you should not instantiate anything in the impl package directly.
@lhazlewood using Jwts.header() doesn't change anything. Standard technique or not compiler won't know which overload version to use, cause both are applicable. This is the simplest thing you can paste and check for yourself:
@Test
public void whatever() {
Header header = Jwts.header();
String payloadWithoutPartner1 = Jwts.builder()
.setHeader(header)
.compact();
}
@lhazlewood Have you tried to compile that snippet?
Hi, am'i the same problem, Are there any solution ?
Yeah, do not use it Header, but just Map<String, Object>. Please note that this map have to be mutable, so do not even try guava or something
@lhazlewood at least 3 users thinks it is a bug. Could you please try to compile my snippet so you can see it for yourself?
Same problem here. I ended up using setHeaderParam() which is simpler anyways.
Casting to map .setHeader((Map<String, Object>) header) works
Like the last entry stated, I used setHeaderParam, instead.
This seems to be a bug in the definition of the interface JwtBuilder. I don't think it is possible to call the method setHeader(x) when x is of type Header. This is because a Header is also a Map<String,Object>, and so Java won't know whether to call the setHeader method with type Header or with type Map<String,Object>.
Well, casting a Header to Map<String, Object> as robrez did might work, but you are still not calling the setHeader with parameter Header, you are calling setHeader with parameter Map<String,Object>.
So I think the code that defines setHeader( Header x) is dead code as it can never be called.
This sort of makes the whole methods of Header building with Jwts.header() and Jwts.jwsHeader() pointless in the sense that you can get a Header, and then put what you want into the header, but then you need to cast it make to a Map<String,Object> in order to build a token with your header... so why not just start out with a Map<String,Object> that is NOT an actual Header, and use that?
Or am I missing something?
(PS I ended up using setHeaderParam as well.
@hong-yi-en spot on. You can't call it with Header as compiler will complain.
@lhazlewood I guess any user that have commented here can fix that (including me) so just tell us how would you like it to be solved and we can move on
It is not possible to use headers created with Jwts.header() in the builder without any compilation warnings or errors.
The only benefit I see of using Header and then casting in the setHeader() method is the use of type-safe getters and setters as stated in the Header Javadocs.
JwsHeader<?> header = Jwts.jwsHeader();
header.setKeyId("key_id");
header.setType("the_type");
...
Jwts.builder().setHeader((Map<String, Object>)header);
I would consider using these type-safe methods a very good thing. Otherwise - why is there even a class JwsHeader?
Just following this up - yes, the API should be cleaned up to avoid this confusion. Thanks for reporting and confirming everyone. We'll track this for a future release, but it remains to be seen if this would require backwards-incompatible changes. If so, those changes would have to wait for 1.0, otherwise, we'll come up with a fix as best as is possible.
Also note: currently the JJWT API uses method names of setHeader and setHeaderParam to mirror with that JWT RFC calls these concepts.
An impedance mismatch here is that the spec calls the entire JSON object with all of its name/value pairs as the Header (singular) and each name/value pair within it as a header parameter, but almost all Java developers refer to these things collectively as 'headers' (plural), and each individual one as a 'header', likely due to HTTP taxonomy.
Perhaps a simplification for Java idioms (rather than RFC taxonomy) can be used:
<T> JwtBuilder setHeader(String name, T value) and
JwtBuilder setHeaders(Map<String, ?> params)
I'm not sure if this is desirable or not however. Using different names than the spec could cause confusion for some. I'm curious what the JJWT community prefers.
Another challenge with changing taxonomy is that corresponding interfaces reflect the specification's taxonomy (as they should really), so changing interfaces might be a no-go. We might be forced to keep the existing nomenclature, which might not be such a bad thing. I think perhaps the real issue is ensuring there are no compiler warnings/errors.
Any update on this issue? Its still persist in the latest version.
It's likely something that will need to wait for a breaking API change @pethaniakshay, but for now, you should be able to cast the param to force the use of the expected method. (or one of the other header related methods)
I just flagged the issue with the "1.0" milestone as well
Many years have passed and this problem has not been solved. Is this funny?
I heard on slack that 1.0 development was started.
This fix has been merged to master.