Skip to content

Commit eef4366

Browse files
committed
fix: Preserve integral Number type in toJsonTree for byte/short/int
The BYTE, SHORT, and INTEGER type adapters' write methods called value(byteValue()), value(shortValue()), and value(intValue()) respectively. Since JsonWriter only has value(long), Java auto-widened the primitive to long, causing JsonTreeWriter.value(long) to store a Long in the JsonPrimitive instead of the original Byte/Short/Integer. Fix by casting the narrowed primitive to Number, which triggers autoboxing to the correct type and resolves to value(Number) instead of value(long). Fixes #2680
1 parent 1fa9b7a commit eef4366

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ public void write(JsonWriter out, Number value) throws IOException {
214214
if (value == null) {
215215
out.nullValue();
216216
} else {
217-
out.value(value.byteValue());
217+
out.value((Number) value.byteValue());
218218
}
219219
}
220220
};
@@ -249,7 +249,7 @@ public void write(JsonWriter out, Number value) throws IOException {
249249
if (value == null) {
250250
out.nullValue();
251251
} else {
252-
out.value(value.shortValue());
252+
out.value((Number) value.shortValue());
253253
}
254254
}
255255
};
@@ -277,7 +277,7 @@ public void write(JsonWriter out, Number value) throws IOException {
277277
if (value == null) {
278278
out.nullValue();
279279
} else {
280-
out.value(value.intValue());
280+
out.value((Number) value.intValue());
281281
}
282282
}
283283
};

gson/src/test/java/com/google/gson/functional/PrimitiveTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,33 @@ public void testIntSerialization() {
161161
assertThat(gson.toJson(1.5, Integer.class)).isEqualTo("1");
162162
}
163163

164+
/** Regression test for https://github.com/google/gson/issues/2680 */
165+
@Test
166+
public void testToJsonTreePreservesIntegralType() {
167+
// toJsonTree should preserve the Number type, not widen byte/short/int to Long
168+
assertThat(gson.toJsonTree((byte) 1, byte.class).getAsNumber().getClass())
169+
.isEqualTo(Byte.class);
170+
assertThat(gson.toJsonTree((byte) 1, Byte.class).getAsNumber().getClass())
171+
.isEqualTo(Byte.class);
172+
173+
assertThat(gson.toJsonTree((short) 1, short.class).getAsNumber().getClass())
174+
.isEqualTo(Short.class);
175+
assertThat(gson.toJsonTree((short) 1, Short.class).getAsNumber().getClass())
176+
.isEqualTo(Short.class);
177+
178+
assertThat(gson.toJsonTree(1, int.class).getAsNumber().getClass()).isEqualTo(Integer.class);
179+
assertThat(gson.toJsonTree(1, Integer.class).getAsNumber().getClass()).isEqualTo(Integer.class);
180+
181+
// Long should remain Long
182+
assertThat(gson.toJsonTree(1L, long.class).getAsNumber().getClass()).isEqualTo(Long.class);
183+
assertThat(gson.toJsonTree(1L, Long.class).getAsNumber().getClass()).isEqualTo(Long.class);
184+
185+
// Narrowing conversion should produce the target type
186+
assertThat(gson.toJsonTree(1.5, Integer.class).getAsNumber().getClass())
187+
.isEqualTo(Integer.class);
188+
assertThat(gson.toJsonTree(1L, Byte.class).getAsNumber().getClass()).isEqualTo(Byte.class);
189+
}
190+
164191
@Test
165192
public void testLongSerialization() {
166193
assertThat(gson.toJson(1L, long.class)).isEqualTo("1");

0 commit comments

Comments
 (0)