Skip to content

Commit

Permalink
Merge dc13b04 into 7805e08
Browse files Browse the repository at this point in the history
  • Loading branch information
lhazlewood committed Sep 18, 2023
2 parents 7805e08 + dc13b04 commit 01266de
Show file tree
Hide file tree
Showing 45 changed files with 2,276 additions and 988 deletions.
18 changes: 16 additions & 2 deletions api/src/main/java/io/jsonwebtoken/JwtBuilder.java
Expand Up @@ -20,6 +20,7 @@
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoder;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.io.Writer;
import io.jsonwebtoken.lang.MapMutator;
import io.jsonwebtoken.security.AeadAlgorithm;
import io.jsonwebtoken.security.InvalidKeyException;
Expand Down Expand Up @@ -885,12 +886,25 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
* @param serializer the serializer to use when converting Map objects to JSON strings.
* @return the builder for method chaining.
* @since 0.10.0
* @deprecated since JJWT_RELEASE_VERSION in favor of the more modern builder-style
* {@link #serializer(Serializer)} method.
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link #jsonWriter(Writer)}
*/
@Deprecated
JwtBuilder serializeToJsonWith(Serializer<Map<String, ?>> serializer);

/**
* Perform Map-to-JSON serialization with the specified writer. This is used by the builder to convert
* JWT/JWS/JWE headers and Claims Maps to JSON strings as required by the JWT specification.
*
* <p>If this method is not called, JJWT will use whatever Writer it can find at runtime, checking for the
* presence of well-known implementations such Jackson, Gson, and org.json. If one of these is not found
* in the runtime classpath, an exception will be thrown when the {@link #compact()} method is invoked.</p>
*
* @param writer the writer to use when converting Map objects to JSON strings.
* @return the builder for method chaining.
* @since JJWT_RELEASE_VERSION
*/
JwtBuilder jsonWriter(Writer<Map<String, ?>> writer);

/**
* Perform Map-to-JSON serialization with the specified Serializer. This is used by the builder to convert
* JWT/JWS/JWE headers and Claims Maps to JSON strings as required by the JWT specification.
Expand Down
6 changes: 5 additions & 1 deletion api/src/main/java/io/jsonwebtoken/io/Deserializer.java
Expand Up @@ -20,15 +20,19 @@
*
* @param <T> the type of object to be returned as a result of deserialization.
* @since 0.10.0
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link io.jsonwebtoken.io.Reader}
*/
@Deprecated
public interface Deserializer<T> {

/**
* Convert the specified formatted data byte array into a Java object.
*
* @param bytes the formatted data byte array to convert
* @return the reconstituted Java object
* @throws DeserializationException if there is a problem converting the byte array to to an object.
* @throws DeserializationException if there is a problem converting the byte array to an object.
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link Reader#read(java.io.Reader)}
*/
@Deprecated
T deserialize(byte[] bytes) throws DeserializationException;
}
36 changes: 36 additions & 0 deletions api/src/main/java/io/jsonwebtoken/io/Reader.java
@@ -0,0 +1,36 @@
/*
* Copyright © 2023 jsonwebtoken.io
*
* 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.
*/
package io.jsonwebtoken.io;

import java.io.IOException;

/**
* A {@code Reader} reads an object from an input stream.
*
* @param <T> the type of object read.
* @since JJWT_RELEASE_VERSION
*/
public interface Reader<T> {

/**
* Reads an object from an input stream, but does not close it; the caller must close the stream as necessary.
*
* @param in the input stream.
* @return the object read from the stream.
* @throws IOException if there is a problem reading from the stream or creating the expected object.
*/
T read(java.io.Reader in) throws IOException;
}
5 changes: 4 additions & 1 deletion api/src/main/java/io/jsonwebtoken/io/Serializer.java
Expand Up @@ -21,7 +21,9 @@
*
* @param <T> The type of object to serialize.
* @since 0.10.0
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link io.jsonwebtoken.io.Writer}
*/
@Deprecated
public interface Serializer<T> {

/**
Expand All @@ -30,7 +32,8 @@ public interface Serializer<T> {
* @param t the object to serialize
* @return the serialized byte array representing the specified object.
* @throws SerializationException if there is a problem converting the object to a byte array.
* @deprecated since JJWT_RELEASE_VERSION in favor of {@link Writer#write(java.io.Writer, Object)}
*/
@Deprecated
byte[] serialize(T t) throws SerializationException;

}
36 changes: 36 additions & 0 deletions api/src/main/java/io/jsonwebtoken/io/Writer.java
@@ -0,0 +1,36 @@
/*
* Copyright © 2023 jsonwebtoken.io
*
* 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.
*/
package io.jsonwebtoken.io;

import java.io.IOException;

/**
* A {@code Writer} writes an object to an output stream.
*
* @param <T> the type of object to write.
* @since JJWT_RELEASE_VERSION
*/
public interface Writer<T> {

/**
* Writes {@code t} to the output stream, but does not close it; the caller must close the stream as necessary.
*
* @param out the output stream.
* @param t the object to write.
* @throws IOException if there is a problem writing.
*/
void write(java.io.Writer out, T t) throws IOException;
}
Expand Up @@ -18,44 +18,44 @@
import com.google.gson.Gson;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.lang.Objects;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

public class GsonDeserializer<T> implements Deserializer<T> {
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public class GsonDeserializer<T> extends GsonReader<T> implements Deserializer<T> {

private final Class<T> returnType;
private final Gson gson;

@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
public GsonDeserializer() {
this(GsonSerializer.DEFAULT_GSON);
super();
}

@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom gson
public GsonDeserializer(Gson gson) {
this(gson, (Class<T>) Object.class);
}

private GsonDeserializer(Gson gson, Class<T> returnType) {
Assert.notNull(gson, "gson cannot be null.");
Assert.notNull(returnType, "Return type cannot be null.");
this.gson = gson;
this.returnType = returnType;
super(gson);
}

@SuppressWarnings("deprecation")
@Deprecated
@Override
public T deserialize(byte[] bytes) throws DeserializationException {
try {
return readValue(bytes);
} catch (IOException e) {
String msg = "Unable to deserialize bytes into a " + returnType.getName() + " instance: " + e.getMessage();
throw new DeserializationException(msg, e);
} catch (Throwable t) {
String msg = "Unable to deserialize JSON: " + t.getMessage();
throw new DeserializationException(msg, t);
}
}

@Deprecated
protected T readValue(byte[] bytes) throws IOException {
return gson.fromJson(new String(bytes, Strings.UTF_8), returnType);
Reader reader = new InputStreamReader(new ByteArrayInputStream(bytes));
try {
return read(reader);
} finally {
Objects.nullSafeClose(reader);
}
}
}
@@ -0,0 +1,58 @@
/*
* Copyright © 2023 jsonwebtoken.io
*
* 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.
*/
package io.jsonwebtoken.gson.io;

import com.google.gson.Gson;
import io.jsonwebtoken.io.Reader;
import io.jsonwebtoken.lang.Assert;

import java.io.IOException;

public class GsonReader<T> implements Reader<T> {

private final Class<T> returnType;
protected final Gson gson;

public GsonReader() {
this(GsonWriter.DEFAULT_GSON);
}

@SuppressWarnings("unchecked")
public GsonReader(Gson gson) {
this(gson, (Class<T>) Object.class);
}

private GsonReader(Gson gson, Class<T> returnType) {
Assert.notNull(gson, "gson cannot be null.");
Assert.notNull(returnType, "Return type cannot be null.");
this.gson = gson;
this.returnType = returnType;
}

@Override
public T read(java.io.Reader in) throws IOException {
try {
return readValue(in);
} catch (Throwable t) {
String msg = "Unable to read JSON as a " + returnType.getName() + " instance: " + t.getMessage();
throw new IOException(msg, t);
}
}

protected T readValue(java.io.Reader reader) {
return gson.fromJson(reader, returnType);
}
}
Expand Up @@ -16,79 +16,48 @@
package io.jsonwebtoken.gson.io;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.io.SerializationException;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.lang.Supplier;
import io.jsonwebtoken.lang.Objects;

public class GsonSerializer<T> implements Serializer<T> {
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

static final Gson DEFAULT_GSON = new GsonBuilder()
.registerTypeHierarchyAdapter(Supplier.class, GsonSupplierSerializer.INSTANCE)
.disableHtmlEscaping().create();
private final Gson gson;
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public class GsonSerializer<T> extends GsonWriter<T> implements Serializer<T> {

@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
public GsonSerializer() {
this(DEFAULT_GSON);
super();
}

@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom gson
public GsonSerializer(Gson gson) {
Assert.notNull(gson, "gson cannot be null.");
this.gson = gson;

//ensure the necessary type adapter has been registered, and if not, throw an error:
String json = this.gson.toJson(TestSupplier.INSTANCE);
if (json.contains("value")) {
String msg = "Invalid Gson instance - it has not been registered with the necessary " +
Supplier.class.getName() + " type adapter. When using the GsonBuilder, ensure this " +
"type adapter is registered by calling gsonBuilder.registerTypeHierarchyAdapter(" +
Supplier.class.getName() + ".class, " +
GsonSupplierSerializer.class.getName() + ".INSTANCE) before calling gsonBuilder.create()";
throw new IllegalArgumentException(msg);
}
super(gson);
}

@SuppressWarnings("deprecation")
@Override
public byte[] serialize(T t) throws SerializationException {
Assert.notNull(t, "Object to serialize cannot be null.");
try {
return writeValueAsBytes(t);
} catch (Exception e) {
String msg = "Unable to serialize object: " + e.getMessage();
throw new SerializationException(msg, e);
}
}

@SuppressWarnings("WeakerAccess") //for testing
protected byte[] writeValueAsBytes(T t) {
Object o;
if (t instanceof byte[]) {
o = Encoders.BASE64.encode((byte[]) t);
} else if (t instanceof char[]) {
o = new String((char[]) t);
} else {
o = t;
} catch (Throwable ex) {
String msg = "Unable to serialize object: " + ex.getMessage();
throw new SerializationException(msg, ex);
}
return this.gson.toJson(o).getBytes(Strings.UTF_8);
}

private static class TestSupplier<T> implements Supplier<T> {

private static final TestSupplier<String> INSTANCE = new TestSupplier<>("test");
private final T value;

private TestSupplier(T value) {
this.value = value;
}

@Override
public T get() {
return value;
protected byte[] writeValueAsBytes(T t) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
OutputStreamWriter writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8);
try {
write(writer, t);
} finally {
Objects.nullSafeClose(writer);
}
return baos.toByteArray();
}
}

0 comments on commit 01266de

Please sign in to comment.