Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions gson/src/main/java/com/google/gson/FieldNamingPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,35 +179,41 @@ public String translateName(Field f) {
static String separateCamelCase(String name, char separator) {
StringBuilder translation = new StringBuilder();
for (int i = 0, length = name.length(); i < length; i++) {
char character = name.charAt(i);
if (Character.isUpperCase(character) && translation.length() != 0) {
translation.append(separator);
}
char character = getCharacter(name, separator, i, translation);
translation.append(character);
}
return translation.toString();
}

private static char getCharacter(String name, char separator, int i, StringBuilder translation) {
char character = name.charAt(i);
if (Character.isUpperCase(character) && translation.length() != 0) {
translation.append(separator);
}
return character;
}

/** Ensures the JSON field names begins with an upper case letter. */
static String upperCaseFirstLetter(String s) {
int length = s.length();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
return s;
}

char uppercased = Character.toUpperCase(c);
// For leading letter only need one substring
if (i == 0) {
return uppercased + s.substring(1);
} else {
return s.substring(0, i) + uppercased + s.substring(i + 1);
}
return getString(s, c, i);
}
}

return s;
}

private static String getString(String s, char c, int i) {
if (Character.isUpperCase(c)) return s;

char uppercased = Character.toUpperCase(c);
// For leading letter only need one substring
if (i != 0) {
return s.substring(0, i) + uppercased + s.substring(i + 1);
}
return uppercased + s.substring(1);
}
}
82 changes: 61 additions & 21 deletions gson/src/main/java/com/google/gson/Gson.java
Original file line number Diff line number Diff line change
Expand Up @@ -604,12 +604,8 @@ public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
}

Map<TypeToken<?>, TypeAdapter<?>> threadCalls = threadLocalAdapterResults.get();
boolean isInitialAdapterRequest = false;
if (threadCalls == null) {
threadCalls = new HashMap<>();
threadLocalAdapterResults.set(threadCalls);
isInitialAdapterRequest = true;
} else {
boolean isInitialAdapterRequest;
if (threadCalls != null) {
// the key and value type parameters always agree
@SuppressWarnings("unchecked")
TypeAdapter<T> ongoingCall = (TypeAdapter<T>) threadCalls.get(type);
Expand All @@ -618,20 +614,16 @@ public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
}
}

threadCalls = new HashMap<>();
threadLocalAdapterResults.set(threadCalls);
isInitialAdapterRequest = true;

TypeAdapter<T> candidate = null;
try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<>();
threadCalls.put(type, call);

for (TypeAdapterFactory factory : factories) {
candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
// Replace future adapter with actual adapter
threadCalls.put(type, candidate);
break;
}
}
candidate = getTypeAdapter(type, candidate, call, threadCalls);
} finally {
if (isInitialAdapterRequest) {
threadLocalAdapterResults.remove();
Expand All @@ -655,6 +647,42 @@ public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
return candidate;
}

/**
* Retrieves a {@link TypeAdapter} for the given {@link TypeToken}. This method scans through
* the registered {@link TypeAdapterFactory} instances to find a suitable adapter for the type.
* If an appropriate adapter is found, it updates the provided {@link FutureTypeAdapter}
* and replaces the future adapter with the actual adapter in the given thread-local adapter map.
*
* @param <T> The type for which to retrieve the type adapter.
* @param type The type token representing the type for which the adapter is being retrieved.
* @param candidate A potential candidate adapter, which may be replaced if another factory
* provides a non-null adapter.
* @param call The future type adapter that will have its delegate set to the found adapter.
* @param threadCalls A map of thread-local type adapters where the future adapter will be
* replaced by the actual adapter once found.
* @return The resolved {@link TypeAdapter} for the given type, or null if none could be found.
*/
private <T> TypeAdapter<T> getTypeAdapter(TypeToken<T> type, TypeAdapter<T> candidate,
FutureTypeAdapter<T> call, Map<TypeToken<?>, TypeAdapter<?>> threadCalls) {
for (TypeAdapterFactory factory : factories) {
candidate = factory.create(this, type);
if (extracted(type, candidate, call, threadCalls)) break;
}

return candidate;
}

private static <T> boolean extracted(TypeToken<T> type, TypeAdapter<T> candidate,
FutureTypeAdapter<T> call, Map<TypeToken<?>, TypeAdapter<?>> threadCalls) {
if (candidate != null) {
call.setDelegate(candidate);
// Replace future adapter with actual adapter
threadCalls.put(type, candidate);
return true;
}
return false;
}

/**
* Returns the type adapter for {@code type}.
*
Expand Down Expand Up @@ -737,9 +765,7 @@ public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeTo
boolean skipPastFound = false;
for (TypeAdapterFactory factory : factories) {
if (!skipPastFound) {
if (factory == skipPast) {
skipPastFound = true;
}
skipPastFound = isSkipPastFound(skipPast, factory);
continue;
}

Expand All @@ -757,6 +783,17 @@ public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeTo
}
}

/**
* Checks if the provided factory matches the skipPast factory.
*
* @param skipPast the factory to be skipped past
* @param factory the factory to compare against the skipPast factory
* @return {@code true} if the factory matches the skipPast factory, otherwise {@code false}
*/
private static boolean isSkipPastFound(TypeAdapterFactory skipPast, TypeAdapterFactory factory) {
return factory == skipPast;
}

/**
* This method serializes the specified object into its equivalent representation as a tree of
* {@link JsonElement}s. This method should be used when the specified object is not a generic
Expand Down Expand Up @@ -865,11 +902,12 @@ public String toJson(Object src, Type typeOfSrc) {
* @see #toJson(Object, Type, Appendable)
*/
public void toJson(Object src, Appendable writer) throws JsonIOException {
if (src != null) {
toJson(src, src.getClass(), writer);
} else {
if (src == null) {
toJson(JsonNull.INSTANCE, writer);
return;
}

toJson(src, src.getClass(), writer);
}

/**
Expand Down Expand Up @@ -923,6 +961,8 @@ public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOE
* @throws JsonIOException if there was a problem writing to the writer
*/
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
if (src == null) return;

@SuppressWarnings("unchecked")
TypeAdapter<Object> adapter = (TypeAdapter<Object>) getAdapter(TypeToken.get(typeOfSrc));

Expand Down
16 changes: 10 additions & 6 deletions gson/src/main/java/com/google/gson/GsonBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -602,17 +602,21 @@ public GsonBuilder disableHtmlEscaping() {
@CanIgnoreReturnValue
public GsonBuilder setDateFormat(String pattern) {
if (pattern != null) {
try {
new SimpleDateFormat(pattern);
} catch (IllegalArgumentException e) {
// Throw exception if it is an invalid date format
throw new IllegalArgumentException("The date pattern '" + pattern + "' is not valid", e);
}
extracted(pattern);
}
this.datePattern = pattern;
return this;
}

private static void extracted(String pattern) {
try {
new SimpleDateFormat(pattern);
} catch (IllegalArgumentException e) {
// Throw exception if it is an invalid date format
throw new IllegalArgumentException("The date pattern '" + pattern + "' is not valid", e);
}
}

/**
* Configures Gson to serialize {@code Date} objects according to the date style value provided.
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
Expand Down
10 changes: 7 additions & 3 deletions gson/src/main/java/com/google/gson/JsonArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,18 @@ public JsonArray(int capacity) {
public JsonArray deepCopy() {
if (!elements.isEmpty()) {
JsonArray result = new JsonArray(elements.size());
for (JsonElement element : elements) {
result.add(element.deepCopy());
}
extracted(result);
return result;
}
return new JsonArray();
}

private void extracted(JsonArray result) {
for (JsonElement element : elements) {
result.add(element.deepCopy());
}
}

/**
* Adds the specified boolean to self.
*
Expand Down
21 changes: 13 additions & 8 deletions gson/src/main/java/com/google/gson/JsonPrimitive.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,12 @@ public boolean isNumber() {
public Number getAsNumber() {
if (value instanceof Number) {
return (Number) value;
} else if (value instanceof String) {
}

if (value instanceof String) {
return new LazilyParsedNumber((String) value);
}

throw new UnsupportedOperationException("Primitive is neither a number nor a string");
}

Expand All @@ -159,9 +162,13 @@ public boolean isString() {
public String getAsString() {
if (value instanceof String) {
return (String) value;
} else if (isNumber()) {
}

if (isNumber()) {
return getAsNumber().toString();
} else if (isBoolean()) {
}

if (isBoolean()) {
return ((Boolean) value).toString();
}
throw new AssertionError("Unexpected value type: " + value.getClass());
Expand Down Expand Up @@ -249,11 +256,9 @@ public byte getAsByte() {
@Override
public char getAsCharacter() {
String s = getAsString();
if (s.isEmpty()) {
throw new UnsupportedOperationException("String value is empty");
} else {
return s.charAt(0);
}
if (s.isEmpty()) throw new UnsupportedOperationException("String value is empty");

return s.charAt(0);
}

/** Returns the hash code of this object. */
Expand Down
18 changes: 11 additions & 7 deletions gson/src/main/java/com/google/gson/ToNumberPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,18 @@ public Number readNumber(JsonReader in) throws IOException {
@Override
public Number readNumber(JsonReader in) throws IOException, JsonParseException {
String value = in.nextString();
if (value.indexOf('.') >= 0) {
if (value.indexOf('.') < 0) {
return getNumber(in, value);
}

return parseAsDouble(value, in);
}

private Number getNumber(JsonReader in, String value) throws IOException {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return parseAsDouble(value, in);
} else {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return parseAsDouble(value, in);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.MalformedJsonException;
import com.google.gson.utils.ArrayUtils;

import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
Expand Down Expand Up @@ -342,7 +344,7 @@ public void promoteNameToValue() throws IOException {
private void push(Object newTop) {
if (stackSize == stack.length) {
int newLength = stackSize * 2;
stack = Arrays.copyOf(stack, newLength);
stack = Arrays.copyOf(stack, stackSize);
pathIndices = Arrays.copyOf(pathIndices, newLength);
pathNames = Arrays.copyOf(pathNames, newLength);
}
Expand Down
Loading
Loading