Merge pull request #351 from jwtk/348-multi-module-project

Migrate to multi-module project
This commit is contained in:
Les Hazlewood 2018-07-20 12:50:16 -04:00 committed by GitHub
commit b4e5e03152
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
190 changed files with 1637 additions and 678 deletions

View File

@ -1,7 +1,6 @@
# https://travis-ci.org/jwtk/jjwt # https://travis-ci.org/jwtk/jjwt
dist: trusty #sudo: required
sudo: required
language: java language: java
jdk: jdk:
- openjdk7 - openjdk7
@ -9,16 +8,15 @@ jdk:
- oraclejdk9 - oraclejdk9
- oraclejdk10 - oraclejdk10
- openjdk10 - openjdk10
- oraclejdk-ea # - openjdk11
- openjdk11 # - oraclejdk-ea
before_install: before_install:
- export BUILD_COVERAGE="$([ $TRAVIS_JDK_VERSION == 'oraclejdk8' ] && echo 'true')" - export BUILD_COVERAGE="$([ $TRAVIS_JDK_VERSION == 'oraclejdk8' ] && echo 'true')"
install: echo "No need to run mvn install -DskipTests then mvn install. Running mvn install." install: true
script: mvn install script: mvn install
after_success: after_success:
- test -z "$BUILD_COVERAGE" || mvn clean test clover:check clover:clover coveralls:report - test -z "$BUILD_COVERAGE" || { mvn clean clover:setup test && mvn -pl . clover:clover clover:check coveralls:report; }

2
NOTICE
View File

@ -1,4 +1,4 @@
The io.jsonwebtoken.codec.impl.Base64 implementation is based on MigBase64 with modifications for Base64 URL support. This The Base64 implementation is based on MigBase64 with modifications for Base64 URL support. This
class's copyright and license notice have been retained and are repeated here per that code's requirements: class's copyright and license notice have been retained and are repeated here per that code's requirements:
**** BEGIN MIGBASE64 NOTICE ***** **** BEGIN MIGBASE64 NOTICE *****

View File

@ -89,7 +89,7 @@ Most complexity is hidden behind a convenient and readable builder-based [fluent
```java ```java
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.crypto.MacProvider; import MacProvider; //TODO: clean up via https://github.com/jwtk/jjwt/issues/350
import java.security.Key; import java.security.Key;
// We need a signing key, so we'll create one just for this example. Usually // We need a signing key, so we'll create one just for this example. Usually
@ -154,7 +154,7 @@ You can use the following rules on your Android projects (see [Proguard Exclusio
-keepnames interface io.jsonwebtoken.* { *; } -keepnames interface io.jsonwebtoken.* { *; }
-dontwarn javax.xml.bind.DatatypeConverter -dontwarn javax.xml.bind.DatatypeConverter
-dontwarn io.jsonwebtoken.impl.Base64Codec -dontwarn Base64Codec
-keepnames class com.fasterxml.jackson.** { *; } -keepnames class com.fasterxml.jackson.** { *; }
-keepnames interface com.fasterxml.jackson.** { *; } -keepnames interface com.fasterxml.jackson.** { *; }

36
api/pom.xml Normal file
View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 JWTK
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.10.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>jjwt-api</artifactId>
<name>JJWT :: API</name>
<packaging>jar</packaging>
<properties>
<jjwt.root>${basedir}/..</jjwt.root>
</properties>
</project>

View File

@ -18,16 +18,16 @@ package io.jsonwebtoken;
/** /**
* Compresses and decompresses byte arrays according to a compression algorithm. * Compresses and decompresses byte arrays according to a compression algorithm.
* *
* @see io.jsonwebtoken.impl.compression.DeflateCompressionCodec * @see CompressionCodecs#DEFLATE
* @see io.jsonwebtoken.impl.compression.GzipCompressionCodec * @see CompressionCodecs#GZIP
* @since 0.6.0 * @since 0.6.0
*/ */
public interface CompressionCodec { public interface CompressionCodec {
/** /**
* The algorithm name to use as the JWT's {@code zip} header value. * The compression algorithm name to use as the JWT's {@code zip} header value.
* *
* @return the algorithm name to use as the JWT's {@code zip} header value. * @return the compression algorithm name to use as the JWT's {@code zip} header value.
*/ */
String getAlgorithmName(); String getAlgorithmName();

View File

@ -20,8 +20,8 @@ package io.jsonwebtoken;
* can use to decompress the JWT body. * can use to decompress the JWT body.
* *
* <p>JJWT's default {@link JwtParser} implementation supports both the * <p>JJWT's default {@link JwtParser} implementation supports both the
* {@link io.jsonwebtoken.impl.compression.DeflateCompressionCodec DEFLATE} * {@link CompressionCodecs#DEFLATE DEFLATE}
* and {@link io.jsonwebtoken.impl.compression.GzipCompressionCodec GZIP} algorithms by default - you do not need to * and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.</p> * specify a {@code CompressionCodecResolver} in these cases.</p>
* *
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement * <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement

View File

@ -1,7 +1,6 @@
package io.jsonwebtoken; package io.jsonwebtoken;
import io.jsonwebtoken.impl.compression.DeflateCompressionCodec; import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.impl.compression.GzipCompressionCodec;
/** /**
* Provides default implementations of the {@link CompressionCodec} interface. * Provides default implementations of the {@link CompressionCodec} interface.
@ -12,15 +11,15 @@ import io.jsonwebtoken.impl.compression.GzipCompressionCodec;
*/ */
public final class CompressionCodecs { public final class CompressionCodecs {
private static final CompressionCodecs INSTANCE = new CompressionCodecs(); private CompressionCodecs() {
} //prevent external instantiation
private CompressionCodecs() {} //prevent external instantiation
/** /**
* Codec implementing the <a href="https://tools.ietf.org/html/rfc7518">JWA</a> standard * Codec implementing the <a href="https://tools.ietf.org/html/rfc7518">JWA</a> standard
* <a href="https://en.wikipedia.org/wiki/DEFLATE">deflate</a> compression algorithm * <a href="https://en.wikipedia.org/wiki/DEFLATE">deflate</a> compression algorithm
*/ */
public static final CompressionCodec DEFLATE = new DeflateCompressionCodec(); public static final CompressionCodec DEFLATE =
Classes.newInstance("io.jsonwebtoken.impl.compression.DeflateCompressionCodec");
/** /**
* Codec implementing the <a href="https://en.wikipedia.org/wiki/Gzip">gzip</a> compression algorithm. * Codec implementing the <a href="https://en.wikipedia.org/wiki/Gzip">gzip</a> compression algorithm.
@ -29,6 +28,7 @@ public final class CompressionCodecs {
* that all parties accessing the token support the gzip algorithm.</p> * that all parties accessing the token support the gzip algorithm.</p>
* <p>If you're concerned about compatibility, the {@link #DEFLATE DEFLATE} code is JWA standards-compliant.</p> * <p>If you're concerned about compatibility, the {@link #DEFLATE DEFLATE} code is JWA standards-compliant.</p>
*/ */
public static final CompressionCodec GZIP = new GzipCompressionCodec(); public static final CompressionCodec GZIP =
Classes.newInstance("io.jsonwebtoken.impl.compression.GzipCompressionCodec");
} }

View File

@ -22,6 +22,7 @@ package io.jsonwebtoken;
* @since 0.6 * @since 0.6
*/ */
public class IncorrectClaimException extends InvalidClaimException { public class IncorrectClaimException extends InvalidClaimException {
public IncorrectClaimException(Header header, Claims claims, String message) { public IncorrectClaimException(Header header, Claims claims, String message) {
super(header, claims, message); super(header, claims, message);
} }

View File

@ -25,6 +25,7 @@ package io.jsonwebtoken;
* @since 0.6 * @since 0.6
*/ */
public class InvalidClaimException extends ClaimJwtException { public class InvalidClaimException extends ClaimJwtException {
private String claimName; private String claimName;
private Object claimValue; private Object claimValue;

View File

@ -15,7 +15,7 @@
*/ */
package io.jsonwebtoken; package io.jsonwebtoken;
import io.jsonwebtoken.codec.Encoder; import io.jsonwebtoken.io.Encoder;
import io.jsonwebtoken.io.Serializer; import io.jsonwebtoken.io.Serializer;
import java.security.Key; import java.security.Key;

View File

@ -15,8 +15,7 @@
*/ */
package io.jsonwebtoken; package io.jsonwebtoken;
import io.jsonwebtoken.codec.Decoder; import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.impl.DefaultClock;
import io.jsonwebtoken.io.Deserializer; import io.jsonwebtoken.io.Deserializer;
import java.security.Key; import java.security.Key;
@ -131,7 +130,7 @@ public interface JwtParser {
/** /**
* Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT. * Sets the {@link Clock} that determines the timestamp to use when validating the parsed JWT.
* The parser uses a {@link DefaultClock DefaultClock} instance by default. * The parser uses a default Clock implementation that simply returns {@code new Date()} when called.
* *
* @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT. * @param clock a {@code Clock} object to return the timestamp to use when validating the parsed JWT.
* @return the parser for method chaining. * @return the parser for method chaining.
@ -259,8 +258,8 @@ public interface JwtParser {
* the same behavior.</p> * the same behavior.</p>
* <h3>Default Support</h3> * <h3>Default Support</h3>
* <p>JJWT's default {@link JwtParser} implementation supports both the * <p>JJWT's default {@link JwtParser} implementation supports both the
* {@link io.jsonwebtoken.impl.compression.DeflateCompressionCodec DEFLATE} * {@link CompressionCodecs#DEFLATE DEFLATE}
* and {@link io.jsonwebtoken.impl.compression.GzipCompressionCodec GZIP} algorithms by default - you do not need to * and {@link CompressionCodecs#GZIP GZIP} algorithms by default - you do not need to
* specify a {@code CompressionCodecResolver} in these cases.</p> * specify a {@code CompressionCodecResolver} in these cases.</p>
* <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement * <p>However, if you want to use a compression algorithm other than {@code DEF} or {@code GZIP}, you must implement
* your own {@link CompressionCodecResolver} and specify that via this method and also when * your own {@link CompressionCodecResolver} and specify that via this method and also when

View File

@ -15,11 +15,7 @@
*/ */
package io.jsonwebtoken; package io.jsonwebtoken;
import io.jsonwebtoken.impl.DefaultClaims; import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.impl.DefaultHeader;
import io.jsonwebtoken.impl.DefaultJwsHeader;
import io.jsonwebtoken.impl.DefaultJwtBuilder;
import io.jsonwebtoken.impl.DefaultJwtParser;
import java.util.Map; import java.util.Map;
@ -31,7 +27,10 @@ import java.util.Map;
*/ */
public final class Jwts { public final class Jwts {
private Jwts(){} private static final Class[] MAP_ARG = new Class[]{Map.class};
private Jwts() {
}
/** /**
* Creates a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs. As this * Creates a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs. As this
@ -41,7 +40,7 @@ public final class Jwts {
* @return a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs. * @return a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs.
*/ */
public static Header header() { public static Header header() {
return new DefaultHeader(); return Classes.newInstance("io.jsonwebtoken.impl.DefaultHeader");
} }
/** /**
@ -52,7 +51,7 @@ public final class Jwts {
* @return a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs. * @return a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs.
*/ */
public static Header header(Map<String, Object> header) { public static Header header(Map<String, Object> header) {
return new DefaultHeader(header); return Classes.newInstance("io.jsonwebtoken.impl.DefaultHeader", MAP_ARG, header);
} }
/** /**
@ -62,7 +61,7 @@ public final class Jwts {
* @see JwtBuilder#setHeader(Header) * @see JwtBuilder#setHeader(Header)
*/ */
public static JwsHeader jwsHeader() { public static JwsHeader jwsHeader() {
return new DefaultJwsHeader(); return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwsHeader");
} }
/** /**
@ -74,7 +73,7 @@ public final class Jwts {
* @see JwtBuilder#setHeader(Header) * @see JwtBuilder#setHeader(Header)
*/ */
public static JwsHeader jwsHeader(Map<String, Object> header) { public static JwsHeader jwsHeader(Map<String, Object> header) {
return new DefaultJwsHeader(header); return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwsHeader", MAP_ARG, header);
} }
/** /**
@ -83,7 +82,7 @@ public final class Jwts {
* @return a new {@link Claims} instance to be used as a JWT body. * @return a new {@link Claims} instance to be used as a JWT body.
*/ */
public static Claims claims() { public static Claims claims() {
return new DefaultClaims(); return Classes.newInstance("io.jsonwebtoken.impl.DefaultClaims");
} }
/** /**
@ -93,7 +92,7 @@ public final class Jwts {
* @return a new {@link Claims} instance populated with the specified name/value pairs. * @return a new {@link Claims} instance populated with the specified name/value pairs.
*/ */
public static Claims claims(Map<String, Object> claims) { public static Claims claims(Map<String, Object> claims) {
return new DefaultClaims(claims); return Classes.newInstance("io.jsonwebtoken.impl.DefaultClaims", MAP_ARG, claims);
} }
/** /**
@ -102,7 +101,7 @@ public final class Jwts {
* @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings. * @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
*/ */
public static JwtParser parser() { public static JwtParser parser() {
return new DefaultJwtParser(); return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtParser");
} }
/** /**
@ -113,6 +112,6 @@ public final class Jwts {
* strings. * strings.
*/ */
public static JwtBuilder builder() { public static JwtBuilder builder() {
return new DefaultJwtBuilder(); return Classes.newInstance("io.jsonwebtoken.impl.DefaultJwtBuilder");
} }
} }

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec.impl; package io.jsonwebtoken.io;
import java.util.Arrays; import java.util.Arrays;
@ -18,6 +18,7 @@ import java.util.Arrays;
* *
* @author Mikael Grev * @author Mikael Grev
* @author Les Hazlewood * @author Les Hazlewood
* @since 0.10.0
*/ */
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
final class Base64 { //final and package-protected on purpose final class Base64 { //final and package-protected on purpose

View File

@ -1,12 +1,13 @@
package io.jsonwebtoken.codec.impl; package io.jsonwebtoken.io;
import io.jsonwebtoken.codec.Decoder;
import io.jsonwebtoken.codec.DecodingException;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
public class Base64Decoder extends Base64Support implements Decoder<String, byte[]> { /**
* @since 0.10.0
*/
class Base64Decoder extends Base64Support implements Decoder<String, byte[]> {
public Base64Decoder() { Base64Decoder() {
super(Base64.DEFAULT); super(Base64.DEFAULT);
} }

View File

@ -1,12 +1,13 @@
package io.jsonwebtoken.codec.impl; package io.jsonwebtoken.io;
import io.jsonwebtoken.codec.Encoder;
import io.jsonwebtoken.codec.EncodingException;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
public class Base64Encoder extends Base64Support implements Encoder<byte[], String> { /**
* @since 0.10.0
*/
class Base64Encoder extends Base64Support implements Encoder<byte[], String> {
public Base64Encoder() { Base64Encoder() {
super(Base64.DEFAULT); super(Base64.DEFAULT);
} }

View File

@ -1,8 +1,11 @@
package io.jsonwebtoken.codec.impl; package io.jsonwebtoken.io;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
public class Base64Support { /**
* @since 0.10.0
*/
class Base64Support {
protected final Base64 base64; protected final Base64 base64;

View File

@ -0,0 +1,11 @@
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
class Base64UrlDecoder extends Base64Decoder {
Base64UrlDecoder() {
super(Base64.URL_SAFE);
}
}

View File

@ -0,0 +1,11 @@
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
class Base64UrlEncoder extends Base64Encoder {
Base64UrlEncoder() {
super(Base64.URL_SAFE);
}
}

View File

@ -1,11 +1,9 @@
package io.jsonwebtoken.codec; package io.jsonwebtoken.io;
import io.jsonwebtoken.JwtException;
/** /**
* @since 0.10.0 * @since 0.10.0
*/ */
public class CodecException extends JwtException { public class CodecException extends IOException {
public CodecException(String message, Throwable cause) { public CodecException(String message, Throwable cause) {
super(message, cause); super(message, cause);

View File

@ -0,0 +1,9 @@
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Decoder<T, R> {
R decode(T t) throws DecodingException;
}

View File

@ -0,0 +1,13 @@
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public final class Decoders {
public static final Decoder<String, byte[]> BASE64 = new ExceptionPropagatingDecoder<>(new Base64Decoder());
public static final Decoder<String, byte[]> BASE64URL = new ExceptionPropagatingDecoder<>(new Base64UrlDecoder());
private Decoders() { //prevent instantiation
}
}

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec; package io.jsonwebtoken.io;
/** /**
* @since 0.10.0 * @since 0.10.0

View File

@ -1,5 +1,8 @@
package io.jsonwebtoken.io; package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class DeserializationException extends SerialException { public class DeserializationException extends SerialException {
public DeserializationException(String msg) { public DeserializationException(String msg) {

View File

@ -1,5 +1,8 @@
package io.jsonwebtoken.io; package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Deserializer<T> { public interface Deserializer<T> {
T deserialize(byte[] bytes) throws DeserializationException; T deserialize(byte[] bytes) throws DeserializationException;

View File

@ -0,0 +1,9 @@
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Encoder<T, R> {
R encode(T t) throws EncodingException;
}

View File

@ -0,0 +1,13 @@
package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public final class Encoders {
public static final Encoder<byte[], String> BASE64 = new ExceptionPropagatingEncoder<>(new Base64Encoder());
public static final Encoder<byte[], String> BASE64URL = new ExceptionPropagatingEncoder<>(new Base64UrlEncoder());
private Encoders() { //prevent instantiation
}
}

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec; package io.jsonwebtoken.io;
/** /**
* @since 0.10.0 * @since 0.10.0

View File

@ -1,14 +1,15 @@
package io.jsonwebtoken.codec.impl; package io.jsonwebtoken.io;
import io.jsonwebtoken.codec.Decoder;
import io.jsonwebtoken.codec.DecodingException;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
public class ExceptionPropagatingDecoder<T, R> implements Decoder<T, R> { /**
* @since 0.10.0
*/
class ExceptionPropagatingDecoder<T, R> implements Decoder<T, R> {
private final Decoder<T, R> decoder; private final Decoder<T, R> decoder;
public ExceptionPropagatingDecoder(Decoder<T, R> decoder) { ExceptionPropagatingDecoder(Decoder<T, R> decoder) {
Assert.notNull(decoder, "Decoder cannot be null."); Assert.notNull(decoder, "Decoder cannot be null.");
this.decoder = decoder; this.decoder = decoder;
} }

View File

@ -1,14 +1,15 @@
package io.jsonwebtoken.codec.impl; package io.jsonwebtoken.io;
import io.jsonwebtoken.codec.Encoder;
import io.jsonwebtoken.codec.EncodingException;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
public class ExceptionPropagatingEncoder<T,R> implements Encoder<T,R> { /**
* @since 0.10.0
*/
class ExceptionPropagatingEncoder<T, R> implements Encoder<T, R> {
private final Encoder<T,R> encoder; private final Encoder<T, R> encoder;
public ExceptionPropagatingEncoder(Encoder<T,R> encoder) { ExceptionPropagatingEncoder(Encoder<T, R> encoder) {
Assert.notNull(encoder, "Encoder cannot be null."); Assert.notNull(encoder, "Encoder cannot be null.");
this.encoder = encoder; this.encoder = encoder;
} }

View File

@ -2,6 +2,9 @@ package io.jsonwebtoken.io;
import io.jsonwebtoken.JwtException; import io.jsonwebtoken.JwtException;
/**
* @since 0.10.0
*/
public class IOException extends JwtException { public class IOException extends JwtException {
public IOException(String msg) { public IOException(String msg) {

View File

@ -1,5 +1,8 @@
package io.jsonwebtoken.io; package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class SerialException extends IOException { public class SerialException extends IOException {
public SerialException(String msg) { public SerialException(String msg) {

View File

@ -1,5 +1,8 @@
package io.jsonwebtoken.io; package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public class SerializationException extends SerialException { public class SerializationException extends SerialException {
public SerializationException(String msg) { public SerializationException(String msg) {

View File

@ -1,5 +1,8 @@
package io.jsonwebtoken.io; package io.jsonwebtoken.io;
/**
* @since 0.10.0
*/
public interface Serializer<T> { public interface Serializer<T> {
byte[] serialize(T t) throws SerializationException; byte[] serialize(T t) throws SerializationException;

View File

@ -5,10 +5,7 @@ package io.jsonwebtoken.lang;
*/ */
public final class Arrays { public final class Arrays {
//for code coverage private Arrays(){} //prevent instantiation
private static final Arrays INSTANCE = new Arrays();
private Arrays(){}
public static int length(byte[] bytes) { public static int length(byte[] bytes) {
return bytes != null ? bytes.length : 0; return bytes != null ? bytes.length : 0;

View File

@ -20,10 +20,7 @@ import java.util.Map;
public final class Assert { public final class Assert {
//for code coverage private Assert(){} //prevent instantiation
private static final Assert INSTANCE = new Assert();
private Assert(){}
/** /**
* Assert a boolean expression, throwing <code>IllegalArgumentException</code> * Assert a boolean expression, throwing <code>IllegalArgumentException</code>

View File

@ -23,9 +23,7 @@ import java.lang.reflect.Constructor;
*/ */
public final class Classes { public final class Classes {
private static final Classes INSTANCE = new Classes(); private Classes() {} //prevent instantiation
private Classes() {}
/** /**
* @since 0.1 * @since 0.1
@ -137,6 +135,12 @@ public final class Classes {
return (T)newInstance(forName(fqcn)); return (T)newInstance(forName(fqcn));
} }
public static <T> T newInstance(String fqcn, Class[] ctorArgTypes, Object... args) {
Class<T> clazz = forName(fqcn);
Constructor<T> ctor = getConstructor(clazz, ctorArgTypes);
return instantiate(ctor, args);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T newInstance(String fqcn, Object... args) { public static <T> T newInstance(String fqcn, Object... args) {
return (T)newInstance(forName(fqcn), args); return (T)newInstance(forName(fqcn), args);

View File

@ -26,10 +26,7 @@ import java.util.Properties;
public final class Collections { public final class Collections {
//for code coverage private Collections(){} //prevent instantiation
private static final Collections INSTANCE = new Collections();
private Collections(){}
/** /**
* Return <code>true</code> if the supplied Collection is <code>null</code> * Return <code>true</code> if the supplied Collection is <code>null</code>

View File

@ -22,10 +22,7 @@ import java.util.Arrays;
public final class Objects { public final class Objects {
//for code coverage private Objects(){} //prevent instantiation
private static final Objects INSTANCE = new Objects();
private Objects(){}
private static final int INITIAL_HASH = 7; private static final int INITIAL_HASH = 7;
private static final int MULTIPLIER = 31; private static final int MULTIPLIER = 31;

View File

@ -21,9 +21,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public final class RuntimeEnvironment { public final class RuntimeEnvironment {
private static final RuntimeEnvironment INSTANCE = new RuntimeEnvironment(); private RuntimeEnvironment(){} //prevent instantiation
private RuntimeEnvironment(){}
private static final String BC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; private static final String BC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider";
@ -33,7 +31,7 @@ public final class RuntimeEnvironment {
public static void enableBouncyCastleIfPossible() { public static void enableBouncyCastleIfPossible() {
if (bcLoaded.get()) { if (!BOUNCY_CASTLE_AVAILABLE || bcLoaded.get()) {
return; return;
} }

View File

@ -31,8 +31,6 @@ import java.util.TreeSet;
public final class Strings { public final class Strings {
private static final Strings INSTANCE = new Strings(); //for code coverage
private static final String FOLDER_SEPARATOR = "/"; private static final String FOLDER_SEPARATOR = "/";
private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
@ -45,7 +43,7 @@ public final class Strings {
public static final Charset UTF_8 = Charset.forName("UTF-8"); public static final Charset UTF_8 = Charset.forName("UTF-8");
private Strings(){} private Strings(){} //prevent instantiation
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// General convenience methods for working with Strings // General convenience methods for working with Strings

View File

@ -0,0 +1,42 @@
package io.jsonwebtoken
import io.jsonwebtoken.lang.Classes
import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import static org.easymock.EasyMock.createMock
import static org.easymock.EasyMock.eq
import static org.easymock.EasyMock.expect
import static org.junit.Assert.assertSame
import static org.powermock.api.easymock.PowerMock.mockStatic
import static org.powermock.api.easymock.PowerMock.replay
import static org.powermock.api.easymock.PowerMock.verify
@RunWith(PowerMockRunner.class)
@PrepareForTest([Classes, CompressionCodecs])
class CompressionCodecsTest {
@Test
void testStatics() {
mockStatic(Classes)
def deflate = createMock(CompressionCodec)
def gzip = createMock(CompressionCodec)
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.compression.DeflateCompressionCodec"))).andReturn(deflate)
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.compression.GzipCompressionCodec"))).andReturn(gzip)
replay Classes, deflate, gzip
assertSame deflate, CompressionCodecs.DEFLATE
assertSame gzip, CompressionCodecs.GZIP
verify Classes, deflate, gzip
//test coverage for private constructor:
new CompressionCodecs()
}
}

View File

@ -19,22 +19,18 @@ import org.junit.Test
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
class CompressionExceptionTest { class CompressionExceptionTest {
@Test @Test
void testDefaultConstructor() { void testDefaultConstructor() {
def exception = new CompressionException("my message") def exception = new CompressionException("my message")
assertEquals "my message", exception.getMessage() assertEquals "my message", exception.getMessage()
} }
@Test @Test
void testConstructorWithCause() { void testConstructorWithCause() {
def ioException = new IOException("root error") def ioException = new IOException("root error")
def exception = new CompressionException("wrapping", ioException) def exception = new CompressionException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage() assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause() assertEquals ioException, exception.getCause()
} }

View File

@ -16,19 +16,42 @@
package io.jsonwebtoken package io.jsonwebtoken
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.* import static org.junit.Assert.*
class ExpiredJwtExceptionTest { class ExpiredJwtExceptionTest {
@Test
void testStringConstructor() {
def header = createMock(Header)
def claims = createMock(Claims)
def msg = 'foo'
replay header, claims
def ex = new ExpiredJwtException(header, claims, msg)
verify header, claims
assertSame ex.header, header
assertSame ex.claims, claims
assertEquals ex.message, msg
}
@Test @Test
void testOverloadedConstructor() { void testOverloadedConstructor() {
def header = Jwts.header() def header = createMock(Header)
def claims = Jwts.claims() def claims = createMock(Claims)
def msg = 'foo' def msg = 'foo'
def cause = new NullPointerException() def cause = new NullPointerException()
replay header, claims
def ex = new ExpiredJwtException(header, claims, msg, cause) def ex = new ExpiredJwtException(header, claims, msg, cause)
verify header, claims
assertSame ex.header, header assertSame ex.header, header
assertSame ex.claims, claims assertSame ex.claims, claims
assertEquals ex.message, msg assertEquals ex.message, msg

View File

@ -17,25 +17,54 @@ package io.jsonwebtoken
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertSame import static org.junit.Assert.assertSame
class IncorrectClaimExceptionTest { class IncorrectClaimExceptionTest {
@Test
void testStringConstructor() {
def header = createMock(Header)
def claims = createMock(Claims)
def msg = 'foo'
def claimName = 'cName'
def claimValue = 'cValue'
replay header, claims
def ex = new IncorrectClaimException(header, claims, msg)
ex.setClaimName(claimName)
ex.setClaimValue(claimValue)
verify header, claims
assertSame ex.header, header
assertSame ex.claims, claims
assertEquals ex.message, msg
assertEquals ex.claimName, claimName
assertEquals ex.claimValue, claimValue
}
@Test @Test
void testOverloadedConstructor() { void testOverloadedConstructor() {
def header = Jwts.header() def header = createMock(Header)
def claims = Jwts.claims() def claims = createMock(Claims)
def msg = 'foo' def msg = 'foo'
def cause = new NullPointerException() def cause = new NullPointerException()
def claimName = 'cName' def claimName = 'cName'
def claimValue = 'cValue' def claimValue = 'cValue'
replay header, claims
def ex = new IncorrectClaimException(header, claims, msg, cause) def ex = new IncorrectClaimException(header, claims, msg, cause)
ex.setClaimName(claimName) ex.setClaimName(claimName)
ex.setClaimValue(claimValue) ex.setClaimValue(claimValue)
verify header, claims
assertSame ex.header, header assertSame ex.header, header
assertSame ex.claims, claims assertSame ex.claims, claims
assertEquals ex.message, msg assertEquals ex.message, msg

View File

@ -17,6 +17,7 @@ package io.jsonwebtoken
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertSame import static org.junit.Assert.assertSame
@ -24,18 +25,22 @@ class InvalidClaimExceptionTest {
@Test @Test
void testOverloadedConstructor() { void testOverloadedConstructor() {
def header = Jwts.header() def header = createMock(Header)
def claims = Jwts.claims() def claims = createMock(Claims)
def msg = 'foo' def msg = 'foo'
def cause = new NullPointerException() def cause = new NullPointerException()
def claimName = 'cName' def claimName = 'cName'
def claimValue = 'cValue' def claimValue = 'cValue'
replay header, claims
def ex = new InvalidClaimException(header, claims, msg, cause) def ex = new InvalidClaimException(header, claims, msg, cause)
ex.setClaimName(claimName) ex.setClaimName(claimName)
ex.setClaimValue(claimValue) ex.setClaimValue(claimValue)
verify header, claims
assertSame ex.header, header assertSame ex.header, header
assertSame ex.claims, claims assertSame ex.claims, claims
assertEquals ex.message, msg assertEquals ex.message, msg

View File

@ -0,0 +1,182 @@
package io.jsonwebtoken
import io.jsonwebtoken.lang.Classes
import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import static org.easymock.EasyMock.createMock
import static org.easymock.EasyMock.eq
import static org.easymock.EasyMock.expect
import static org.easymock.EasyMock.same
import static org.junit.Assert.assertSame
import static org.powermock.api.easymock.PowerMock.mockStatic
import static org.powermock.api.easymock.PowerMock.replay
import static org.powermock.api.easymock.PowerMock.reset
import static org.powermock.api.easymock.PowerMock.verify
@RunWith(PowerMockRunner.class)
@PrepareForTest([Classes, Jwts])
class JwtsTest {
@Test
void testPrivateCtor() { //for code coverage only
new Jwts()
}
@Test
void testHeader() {
mockStatic(Classes)
def instance = createMock(Header)
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.DefaultHeader"))).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.header()
verify Classes, instance
}
@Test
void testHeaderFromMap() {
mockStatic(Classes)
def map = [:]
def instance = createMock(Header)
expect(Classes.newInstance(
eq("io.jsonwebtoken.impl.DefaultHeader"),
same(Jwts.MAP_ARG),
same(map))
).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.header(map)
verify Classes, instance
}
@Test
void testJwsHeader() {
mockStatic(Classes)
def instance = createMock(JwsHeader)
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.DefaultJwsHeader"))).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.jwsHeader()
verify Classes, instance
}
@Test
void testJwsHeaderFromMap() {
mockStatic(Classes)
def map = [:]
def instance = createMock(JwsHeader)
expect(Classes.newInstance(
eq("io.jsonwebtoken.impl.DefaultJwsHeader"),
same(Jwts.MAP_ARG),
same(map))
).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.jwsHeader(map)
verify Classes, instance
}
@Test
void testClaims() {
mockStatic(Classes)
def instance = createMock(Claims)
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.DefaultClaims"))).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.claims()
verify Classes, instance
}
@Test
void testClaimsFromMap() {
mockStatic(Classes)
def map = [:]
def instance = createMock(Claims)
expect(Classes.newInstance(
eq("io.jsonwebtoken.impl.DefaultClaims"),
same(Jwts.MAP_ARG),
same(map))
).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.claims(map)
verify Classes, instance
}
@Test
void testParser() {
mockStatic(Classes)
def instance = createMock(JwtParser)
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.DefaultJwtParser"))).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.parser()
verify Classes, instance
}
@Test
void testBuilder() {
mockStatic(Classes)
//JwtBuilder loads SignatureAlgorithm which in turn uses RuntimeEnvironment which in turn checks for BC:
expect(Classes.isAvailable(eq("org.bouncycastle.jce.provider.BouncyCastleProvider"))).andReturn(false)
replay Classes
def instance = createMock(JwtBuilder)
verify Classes
reset Classes
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.DefaultJwtBuilder"))).andReturn(instance)
replay Classes, instance
assertSame instance, Jwts.builder()
verify Classes, instance
}
}

View File

@ -0,0 +1,22 @@
package io.jsonwebtoken
import org.junit.Test
import static org.junit.Assert.assertEquals
class MalformedJwtExceptionTest {
@Test
void testStringConstructor() {
def exception = new MalformedJwtException("my message")
assertEquals "my message", exception.getMessage()
}
@Test
void testCauseConstructor() {
def ioException = new IOException("root error")
def exception = new MalformedJwtException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause()
}
}

View File

@ -17,25 +17,54 @@ package io.jsonwebtoken
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertSame import static org.junit.Assert.assertSame
class MissingClaimExceptionTest { class MissingClaimExceptionTest {
@Test
void testStringConstructor() {
def header = createMock(Header)
def claims = createMock(Claims)
def msg = 'foo'
def claimName = 'cName'
def claimValue = 'cValue'
replay header, claims
def ex = new MissingClaimException(header, claims, msg)
ex.setClaimName(claimName)
ex.setClaimValue(claimValue)
verify header, claims
assertSame ex.header, header
assertSame ex.claims, claims
assertEquals ex.message, msg
assertEquals ex.claimName, claimName
assertEquals ex.claimValue, claimValue
}
@Test @Test
void testOverloadedConstructor() { void testOverloadedConstructor() {
def header = Jwts.header() def header = createMock(Header)
def claims = Jwts.claims() def claims = createMock(Claims)
def msg = 'foo' def msg = 'foo'
def cause = new NullPointerException() def cause = new NullPointerException()
def claimName = 'cName' def claimName = 'cName'
def claimValue = 'cValue' def claimValue = 'cValue'
replay header, claims
def ex = new MissingClaimException(header, claims, msg, cause) def ex = new MissingClaimException(header, claims, msg, cause)
ex.setClaimName(claimName) ex.setClaimName(claimName)
ex.setClaimValue(claimValue) ex.setClaimValue(claimValue)
verify header, claims
assertSame ex.header, header assertSame ex.header, header
assertSame ex.claims, claims assertSame ex.claims, claims
assertEquals ex.message, msg assertEquals ex.message, msg

View File

@ -16,19 +16,42 @@
package io.jsonwebtoken package io.jsonwebtoken
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.*
import static org.junit.Assert.* import static org.junit.Assert.*
class PrematureJwtExceptionTest { class PrematureJwtExceptionTest {
@Test
void testStringConstructor() {
def header = createMock(Header)
def claims = createMock(Claims)
def msg = 'foo'
replay header, claims
def ex = new PrematureJwtException(header, claims, msg)
verify header, claims
assertSame ex.header, header
assertSame ex.claims, claims
assertEquals ex.message, msg
}
@Test @Test
void testOverloadedConstructor() { void testOverloadedConstructor() {
def header = Jwts.header() def header = createMock(Header)
def claims = Jwts.claims() def claims = createMock(Claims)
def msg = 'foo' def msg = 'foo'
def cause = new NullPointerException() def cause = new NullPointerException()
replay header, claims
def ex = new PrematureJwtException(header, claims, msg, cause) def ex = new PrematureJwtException(header, claims, msg, cause)
verify header, claims
assertSame ex.header, header assertSame ex.header, header
assertSame ex.claims, claims assertSame ex.claims, claims
assertEquals ex.message, msg assertEquals ex.message, msg

View File

@ -6,15 +6,20 @@ import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertSame import static org.junit.Assert.assertSame
class RequiredTypeExceptionTest { class RequiredTypeExceptionTest {
@Test
void testStringConstructor() {
def msg = 'foo'
def ex = new RequiredTypeException(msg)
assertEquals ex.message, msg
}
@Test @Test
void testOverloadedConstructor() { void testOverloadedConstructor() {
def msg = 'foo' def msg = 'foo'
def cause = new NullPointerException() def cause = new NullPointerException()
def ex = new RequiredTypeException(msg, cause) def ex = new RequiredTypeException(msg, cause)
assertEquals ex.message, msg assertEquals ex.message, msg
assertSame ex.cause, cause assertSame ex.cause, cause
} }
} }

View File

@ -0,0 +1,22 @@
package io.jsonwebtoken
import org.junit.Test
import static org.junit.Assert.assertEquals
class SignatureExceptionTest {
@Test
void testStringConstructor() {
def exception = new SignatureException("my message")
assertEquals "my message", exception.getMessage()
}
@Test
void testCauseConstructor() {
def ioException = new IOException("root error")
def exception = new SignatureException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause()
}
}

View File

@ -0,0 +1,102 @@
package io.jsonwebtoken
import org.junit.Test
import javax.crypto.spec.SecretKeySpec
import static org.easymock.EasyMock.*
import static org.junit.Assert.*
class SigningKeyResolverAdapterTest {
@Test(expected=UnsupportedJwtException) //should throw since called but not overridden
void testDefaultResolveSigningKeyBytesFromClaims() {
def header = createMock(JwsHeader)
def claims = createMock(Claims)
new SigningKeyResolverAdapter().resolveSigningKeyBytes(header, claims)
}
@Test(expected=UnsupportedJwtException) //should throw since called but not overridden
void testDefaultResolveSigningKeyBytesFromStringPayload() {
def header = createMock(JwsHeader)
new SigningKeyResolverAdapter().resolveSigningKeyBytes(header, "hi")
}
@Test
void testResolveSigningKeyHmac() {
JwsHeader header = createMock(JwsHeader)
Claims claims = createMock(Claims)
byte[] bytes = new byte[32]
new Random().nextBytes(bytes)
expect(header.getAlgorithm()).andReturn("HS256")
replay header, claims
def adapter = new SigningKeyResolverAdapter() {
@Override
byte[] resolveSigningKeyBytes(JwsHeader h, Claims c) {
assertSame header, h
assertSame claims, c
return bytes
}
}
def key = adapter.resolveSigningKey(header, claims)
verify header, claims
assertTrue key instanceof SecretKeySpec
assertEquals 'HmacSHA256', key.algorithm
assertTrue Arrays.equals(bytes, key.encoded)
}
@Test(expected=IllegalArgumentException)
void testResolveSigningKeyDefaultWithoutHmac() {
JwsHeader header = createMock(JwsHeader)
Claims claims = createMock(Claims)
expect(header.getAlgorithm()).andReturn("RS256")
replay header, claims
new SigningKeyResolverAdapter().resolveSigningKey(header, claims)
}
@Test
void testResolveSigningKeyPayloadHmac() {
JwsHeader header = createMock(JwsHeader)
byte[] bytes = new byte[32]
new Random().nextBytes(bytes)
expect(header.getAlgorithm()).andReturn("HS256")
replay header
def adapter = new SigningKeyResolverAdapter() {
@Override
byte[] resolveSigningKeyBytes(JwsHeader h, String s) {
assertSame header, h
assertEquals 'hi', s
return bytes
}
}
def key = adapter.resolveSigningKey(header, 'hi')
verify header
assertTrue key instanceof SecretKeySpec
assertEquals 'HmacSHA256', key.algorithm
assertTrue Arrays.equals(bytes, key.encoded)
}
@Test(expected=IllegalArgumentException)
void testResolveSigningKeyPayloadWithoutHmac() {
JwsHeader header = createMock(JwsHeader)
expect(header.getAlgorithm()).andReturn("RS256")
replay header
new SigningKeyResolverAdapter().resolveSigningKey(header, 'hi')
}
}

View File

@ -0,0 +1,22 @@
package io.jsonwebtoken
import org.junit.Test
import static org.junit.Assert.assertEquals
class UnsupportedJwtExceptionTest {
@Test
void testStringConstructor() {
def exception = new UnsupportedJwtException("my message")
assertEquals "my message", exception.getMessage()
}
@Test
void testCauseConstructor() {
def ioException = new IOException("root error")
def exception = new UnsupportedJwtException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause()
}
}

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec.impl package io.jsonwebtoken.io
import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.lang.Strings
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec.impl package io.jsonwebtoken.io
import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.lang.Strings
import org.junit.Test import org.junit.Test

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec.impl package io.jsonwebtoken.io
import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.lang.Strings
import org.junit.Test import org.junit.Test
@ -82,60 +82,86 @@ class Base64Test {
assertEquals PLAINTEXT, new String(resultBytes, Strings.UTF_8) assertEquals PLAINTEXT, new String(resultBytes, Strings.UTF_8)
} }
private static String BASE64(String s) { private static String encode(String s) {
byte[] bytes = s.getBytes(Strings.UTF_8); byte[] bytes = s.getBytes(Strings.UTF_8);
return Base64.DEFAULT.encodeToString(bytes, false) return Base64.DEFAULT.encodeToString(bytes, false)
} }
private static String decode(String s) {
byte[] bytes = Base64.DEFAULT.decodeFast(s.toCharArray())
return new String(bytes, Strings.UTF_8)
}
@Test // https://tools.ietf.org/html/rfc4648#page-12 @Test // https://tools.ietf.org/html/rfc4648#page-12
void testRfc4648Base64TestVectors() { void testRfc4648Base64TestVectors() {
assertEquals "", BASE64("") assertEquals "", encode("")
assertEquals "", decode("")
assertEquals "Zg==", BASE64("f") assertEquals "Zg==", encode("f")
assertEquals "f", decode("Zg==")
assertEquals "Zm8=", BASE64("fo") assertEquals "Zm8=", encode("fo")
assertEquals "fo", decode("Zm8=")
assertEquals "Zm9v", BASE64("foo") assertEquals "Zm9v", encode("foo")
assertEquals "foo", decode("Zm9v")
assertEquals "Zm9vYg==", BASE64("foob") assertEquals "Zm9vYg==", encode("foob")
assertEquals "foob", decode("Zm9vYg==")
assertEquals "Zm9vYmE=", BASE64("fooba") assertEquals "Zm9vYmE=", encode("fooba")
assertEquals "fooba", decode("Zm9vYmE=")
assertEquals "Zm9vYmFy", BASE64("foobar") assertEquals "Zm9vYmFy", encode("foobar")
assertEquals "foobar", decode("Zm9vYmFy")
def input = 'special: [\r\n \t], ascii[32..126]: [ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~]\n' def input = 'special: [\r\n \t], ascii[32..126]: [ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~]\n'
def expected = "c3BlY2lhbDogWw0KIAldLCBhc2NpaVszMi4uMTI2XTogWyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+XQo=" def expected = "c3BlY2lhbDogWw0KIAldLCBhc2NpaVszMi4uMTI2XTogWyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+XQo="
assertEquals expected, BASE64(input) assertEquals expected, encode(input)
assertEquals input, decode(expected)
} }
private static String BASE64URL(String s) { private static String urlEncode(String s) {
byte[] bytes = s.getBytes(Strings.UTF_8); byte[] bytes = s.getBytes(Strings.UTF_8);
return Base64.URL_SAFE.encodeToString(bytes, false) return Base64.URL_SAFE.encodeToString(bytes, false)
} }
private static String urlDecode(String s) {
byte[] bytes = Base64.URL_SAFE.decodeFast(s.toCharArray())
return new String(bytes, Strings.UTF_8)
}
@Test //same test vectors above, but with padding removed & some specials swapped: https://brockallen.com/2014/10/17/base64url-encoding/ @Test //same test vectors above, but with padding removed & some specials swapped: https://brockallen.com/2014/10/17/base64url-encoding/
void testRfc4648Base64UrlTestVectors() { void testRfc4648Base64UrlTestVectors() {
assertEquals "", BASE64URL("") assertEquals "", urlEncode("")
assertEquals "", urlDecode("")
assertEquals "Zg", BASE64URL("f") //base64 = 2 padding chars, base64url = no padding needed assertEquals "Zg", urlEncode("f") //base64 = 2 padding chars, base64url = no padding needed
assertEquals "f", urlDecode("Zg")
assertEquals "Zm8", BASE64URL("fo") //base64 = 1 padding char, base64url = no padding needed assertEquals "Zm8", urlEncode("fo") //base64 = 1 padding char, base64url = no padding needed
assertEquals "fo", urlDecode("Zm8")
assertEquals "Zm9v", BASE64URL("foo") assertEquals "Zm9v", urlEncode("foo")
assertEquals "foo", urlDecode("Zm9v")
assertEquals "Zm9vYg", BASE64URL("foob") //base64 = 2 padding chars, base64url = no padding needed assertEquals "Zm9vYg", urlEncode("foob") //base64 = 2 padding chars, base64url = no padding needed
assertEquals "foob", urlDecode("Zm9vYg")
assertEquals "Zm9vYmE", BASE64URL("fooba") //base64 = 1 padding char, base64url = no padding needed assertEquals "Zm9vYmE", urlEncode("fooba") //base64 = 1 padding char, base64url = no padding needed
assertEquals "fooba", urlDecode("Zm9vYmE")
assertEquals "Zm9vYmFy", BASE64URL("foobar") assertEquals "Zm9vYmFy", urlEncode("foobar")
assertEquals "foobar", urlDecode("Zm9vYmFy")
def input = 'special: [\r\n \t], ascii[32..126]: [ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~]\n' def input = 'special: [\r\n \t], ascii[32..126]: [ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~]\n'
def expected = "c3BlY2lhbDogWw0KIAldLCBhc2NpaVszMi4uMTI2XTogWyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+XQo=" def expected = "c3BlY2lhbDogWw0KIAldLCBhc2NpaVszMi4uMTI2XTogWyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+XQo="
.replace("=", "") .replace("=", "")
.replace("+", "-") .replace("+", "-")
.replace("/", "_") .replace("/", "_")
assertEquals expected, BASE64URL(input) assertEquals expected, urlEncode(input)
assertEquals input, urlDecode(expected)
} }
} }

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec package io.jsonwebtoken.io
import org.junit.Test import org.junit.Test
@ -8,7 +8,7 @@ class CodecExceptionTest {
@Test @Test
void testConstructorWithCause() { void testConstructorWithCause() {
def ioException = new IOException("root error") def ioException = new java.io.IOException("root error")
def exception = new CodecException("wrapping", ioException) def exception = new CodecException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage() assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause() assertEquals ioException, exception.getCause()

View File

@ -0,0 +1,22 @@
package io.jsonwebtoken.io
import org.junit.Test
import static org.junit.Assert.*
class DecodersTest {
@Test
void testBase64() {
new Decoders() //not allowed in java, including here only to pass test coverage assertions
assertTrue Decoders.BASE64 instanceof ExceptionPropagatingDecoder
assertTrue Decoders.BASE64.decoder instanceof Base64Decoder
}
@Test
void testBase64Url() {
assertTrue Decoders.BASE64URL instanceof ExceptionPropagatingDecoder
assertTrue Decoders.BASE64URL.decoder instanceof Base64UrlDecoder
}
}

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec package io.jsonwebtoken.io
import org.junit.Test import org.junit.Test
@ -8,7 +8,7 @@ class DecodingExceptionTest {
@Test @Test
void testConstructorWithCause() { void testConstructorWithCause() {
def ioException = new IOException("root error") def ioException = new java.io.IOException("root error")
def exception = new DecodingException("wrapping", ioException) def exception = new DecodingException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage() assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause() assertEquals ioException, exception.getCause()

View File

@ -0,0 +1,22 @@
package io.jsonwebtoken.io
import org.junit.Test
import static org.junit.Assert.assertEquals
class DeserializationExceptionTest {
@Test
void testDefaultConstructor() {
def exception = new DeserializationException("my message")
assertEquals "my message", exception.getMessage()
}
@Test
void testConstructorWithCause() {
def ioException = new java.io.IOException("root error")
def exception = new DeserializationException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause()
}
}

View File

@ -0,0 +1,21 @@
package io.jsonwebtoken.io
import org.junit.Test
import static org.junit.Assert.*
class EncodersTest {
@Test
void testBase64() {
new Encoders() //not allowed in java, including here only to pass test coverage assertions
assertTrue Encoders.BASE64 instanceof ExceptionPropagatingEncoder
assertTrue Encoders.BASE64.encoder instanceof Base64Encoder
}
@Test
void testBase64Url() {
assertTrue Encoders.BASE64URL instanceof ExceptionPropagatingEncoder
assertTrue Encoders.BASE64URL.encoder instanceof Base64UrlEncoder
}
}

View File

@ -1,4 +1,4 @@
package io.jsonwebtoken.codec package io.jsonwebtoken.io
import org.junit.Test import org.junit.Test
@ -8,7 +8,7 @@ class EncodingExceptionTest {
@Test @Test
void testConstructorWithCause() { void testConstructorWithCause() {
def ioException = new IOException("root error") def ioException = new java.io.IOException("root error")
def exception = new EncodingException("wrapping", ioException) def exception = new EncodingException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage() assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause() assertEquals ioException, exception.getCause()

View File

@ -1,8 +1,5 @@
package io.jsonwebtoken.codec.impl package io.jsonwebtoken.io
import io.jsonwebtoken.codec.Decoder
import io.jsonwebtoken.codec.DecodingException
import io.jsonwebtoken.codec.EncodingException
import org.junit.Test import org.junit.Test
import static org.junit.Assert.* import static org.junit.Assert.*
@ -25,7 +22,7 @@ class ExceptionPropagatingDecoderTest {
def decoder = new ExceptionPropagatingDecoder(new Decoder() { def decoder = new ExceptionPropagatingDecoder(new Decoder() {
@Override @Override
Object decode(Object o) throws DecodingException { Object decode(Object o) throws DecodingException {
throw new DecodingException("problem", new IOException("dummy")) throw new DecodingException("problem", new java.io.IOException("dummy"))
} }
}) })
try { try {

View File

@ -1,7 +1,5 @@
package io.jsonwebtoken.codec.impl package io.jsonwebtoken.io
import io.jsonwebtoken.codec.Encoder
import io.jsonwebtoken.codec.EncodingException
import org.junit.Test import org.junit.Test
import static org.junit.Assert.* import static org.junit.Assert.*
@ -25,7 +23,7 @@ class ExceptionPropagatingEncoderTest {
def encoder = new ExceptionPropagatingEncoder(new Encoder() { def encoder = new ExceptionPropagatingEncoder(new Encoder() {
@Override @Override
Object encode(Object o) throws EncodingException { Object encode(Object o) throws EncodingException {
throw new EncodingException("problem", new IOException("dummy")) throw new EncodingException("problem", new java.io.IOException("dummy"))
} }
}) })
try { try {

View File

@ -0,0 +1,22 @@
package io.jsonwebtoken.io
import org.junit.Test
import static org.junit.Assert.assertEquals
class SerializationExceptionTest {
@Test
void testDefaultConstructor() {
def exception = new SerializationException("my message")
assertEquals "my message", exception.getMessage()
}
@Test
void testConstructorWithCause() {
def ioException = new java.io.IOException("root error")
def exception = new SerializationException("wrapping", ioException)
assertEquals "wrapping", exception.getMessage()
assertEquals ioException, exception.getCause()
}
}

48
core/pom.xml Normal file
View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 JWTK
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.10.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>jjwt-core</artifactId>
<name>JJWT :: Core</name>
<packaging>jar</packaging>
<properties>
<jjwt.root>${basedir}/..</jjwt.root>
</properties>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 JWTK
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.10.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>jjwt-jackson</artifactId>
<name>JJWT :: Extensions :: Jackson</name>
<packaging>jar</packaging>
<properties>
<jjwt.root>${basedir}/../..</jjwt.root>
</properties>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,14 +1,13 @@
package io.jsonwebtoken.io.impl.jackson; package io.jsonwebtoken.io;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator /**
* @since 0.10.0
*/
public class JacksonDeserializer<T> implements Deserializer<T> { public class JacksonDeserializer<T> implements Deserializer<T> {
private final Class<T> returnType; private final Class<T> returnType;
@ -21,7 +20,7 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper @SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper
public JacksonDeserializer(ObjectMapper objectMapper) { public JacksonDeserializer(ObjectMapper objectMapper) {
this(objectMapper, (Class<T>) Map.class); this(objectMapper, (Class<T>) Object.class);
} }
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) { private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {

View File

@ -1,11 +1,12 @@
package io.jsonwebtoken.io.impl.jackson; package io.jsonwebtoken.io;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.io.SerializationException;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
/**
* @since 0.10.0
*/
public class JacksonSerializer<T> implements Serializer<T> { public class JacksonSerializer<T> implements Serializer<T> {
static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper(); static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper();

View File

@ -1,14 +1,10 @@
package io.jsonwebtoken.io.impl.jackson package io.jsonwebtoken.io
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.jsonwebtoken.io.DeserializationException
import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.lang.Strings
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.createMock import static org.easymock.EasyMock.*
import static org.easymock.EasyMock.expect
import static org.easymock.EasyMock.replay
import static org.easymock.EasyMock.verify
import static org.junit.Assert.* import static org.junit.Assert.*
class JacksonDeserializerTest { class JacksonDeserializerTest {
@ -42,13 +38,13 @@ class JacksonDeserializerTest {
@Test @Test
void testDeserializeFailsWithJsonProcessingException() { void testDeserializeFailsWithJsonProcessingException() {
def ex = createMock(IOException) def ex = createMock(java.io.IOException)
expect(ex.getMessage()).andReturn('foo') expect(ex.getMessage()).andReturn('foo')
def deserializer = new JacksonDeserializer() { def deserializer = new JacksonDeserializer() {
@Override @Override
protected Object readValue(byte[] bytes) throws IOException { protected Object readValue(byte[] bytes) throws java.io.IOException {
throw ex throw ex
} }
} }
@ -59,7 +55,7 @@ class JacksonDeserializerTest {
deserializer.deserialize('{"hello":"世界"}'.getBytes(Strings.UTF_8)) deserializer.deserialize('{"hello":"世界"}'.getBytes(Strings.UTF_8))
fail() fail()
} catch (DeserializationException se) { } catch (DeserializationException se) {
assertEquals 'Unable to deserialize bytes into a java.util.Map instance: foo', se.getMessage() assertEquals 'Unable to deserialize bytes into a java.lang.Object instance: foo', se.getMessage()
assertSame ex, se.getCause() assertSame ex, se.getCause()
} }

View File

@ -1,16 +1,11 @@
package io.jsonwebtoken.io.impl.jackson package io.jsonwebtoken.io
import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.jsonwebtoken.codec.Encoder
import io.jsonwebtoken.io.SerializationException
import io.jsonwebtoken.lang.Strings import io.jsonwebtoken.lang.Strings
import org.junit.Test import org.junit.Test
import static org.easymock.EasyMock.createMock import static org.easymock.EasyMock.*
import static org.easymock.EasyMock.expect
import static org.easymock.EasyMock.replay
import static org.easymock.EasyMock.verify
import static org.junit.Assert.* import static org.junit.Assert.*
class JacksonSerializerTest { class JacksonSerializerTest {
@ -44,8 +39,7 @@ class JacksonSerializerTest {
@Test @Test
void testByteArray() { //expect Base64 string by default: void testByteArray() { //expect Base64 string by default:
byte[] bytes = "hi".getBytes(Strings.UTF_8) byte[] bytes = "hi".getBytes(Strings.UTF_8)
String encoded = Encoder.BASE64.encode(bytes) String expected = '"aGk="' as String //base64(hi) --> aGk=
String expected = "\"$encoded\"" as String
byte[] result = new JacksonSerializer().serialize(bytes) byte[] result = new JacksonSerializer().serialize(bytes)
assertEquals expected, new String(result, Strings.UTF_8) assertEquals expected, new String(result, Strings.UTF_8)
} }
@ -53,10 +47,8 @@ class JacksonSerializerTest {
@Test @Test
void testEmptyByteArray() { //expect Base64 string by default: void testEmptyByteArray() { //expect Base64 string by default:
byte[] bytes = new byte[0] byte[] bytes = new byte[0]
String encoded = Encoder.BASE64.encode(bytes)
String expected = "\"$encoded\"" as String
byte[] result = new JacksonSerializer().serialize(bytes) byte[] result = new JacksonSerializer().serialize(bytes)
assertEquals expected, new String(result, Strings.UTF_8) assertEquals '""', new String(result, Strings.UTF_8)
} }
@Test @Test

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2018 JWTK
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.10.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>jjwt-orgjson</artifactId>
<name>JJWT :: Extensions :: org.json</name>
<packaging>jar</packaging>
<properties>
<jjwt.root>${basedir}/../..</jjwt.root>
</properties>
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
</dependencies>
</project>

Some files were not shown because too many files have changed in this diff Show More