번호 처리 방법JSON 응답의 역직렬화 시 Gson을 사용하는 FormatException
Gson과 함께 JSON의 응답을 읽고 있는데, 이 답변은 가끔 A/S가 반환됩니다.NumberFormatException
예상대로int
값이 빈 문자열로 설정됩니다.이런 종류의 예외에 대처하는 가장 좋은 방법이 무엇인지 궁금합니다.값이 빈 문자열일 경우 역직렬화는 0이어야 합니다.
예상 JSON 응답:
{
"name" : "Test1",
"runtime" : 90
}
그러나 실행 시 문자열이 비어 있을 수 있습니다.
{
"name" : "Test2",
"runtime" : ""
}
Java 클래스는 다음과 같습니다.
public class Foo
{
private String name;
private int runtime;
}
디시리얼라이제이션은 다음과 같습니다.
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
Gson gson = new Gson();
Foo foo = gson.fromJson(input, Foo.class);
그 결과,com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
int 값 대신 빈 문자열이 반환되기 때문입니다.
Gson에게 "유형의 필드를 역직렬화하고 번호가 있는 경우"라고 말할 수 있는 방법이 있습니까?Format Exception, 기본값 0"을 반환합니다.
이 문제를 해결하려면String
의 유형으로서runtime
대신 필드int
그러나 이러한 오류를 처리하는 더 나은 방법이 있을 수 있습니다.
여기 제가 만든 예가 있습니다.Long
type. 이것이 더 나은 옵션입니다.
public class LongTypeAdapter extends TypeAdapter<Long> {
@Override
public Long read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
String stringValue = reader.nextString();
try {
Long value = Long.valueOf(stringValue);
return value;
} catch (NumberFormatException e) {
return null;
}
}
@Override
public void write(JsonWriter writer, Long value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(value);
}
}
다음을 사용하여 어댑터 등록Gson
util:
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new LongTypeAdapter()).create();
처음에, 나는 Integer values에 대한 일반적인 커스텀 타입 어댑터를 쓰려고 했다.NumberFormatException
0을 반환하지만 Gson은 TypeAdapters를 원시 유형으로 허용하지 않습니다.
java.lang.IllegalArgumentException: Cannot register type adapters for class java.lang.Integer
그 후 새로운 타입을 도입했습니다.FooRuntime
를 위해runtime
필드, 즉Foo
클래스는 다음과 같습니다.
public class Foo
{
private String name;
private FooRuntime runtime;
public int getRuntime()
{
return runtime.getValue();
}
}
public class FooRuntime
{
private int value;
public FooRuntime(int runtime)
{
this.value = runtime;
}
public int getValue()
{
return value;
}
}
유형 어댑터는 사용자 지정 직렬화 프로세스를 처리합니다.
public class FooRuntimeTypeAdapter implements JsonDeserializer<FooRuntime>, JsonSerializer<FooRuntime>
{
public FooRuntime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
int runtime;
try
{
runtime = json.getAsInt();
}
catch (NumberFormatException e)
{
runtime = 0;
}
return new FooRuntime(runtime);
}
public JsonElement serialize(FooRuntime src, Type typeOfSrc, JsonSerializationContext context)
{
return new JsonPrimitive(src.getValue());
}
}
이 시점에서,GsonBuilder
타입 어댑터를 등록하기 위해서, 빈 문자열은, 송신 대신에 0 으로 해석됩니다.NumberFormatException
.
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(FooRuntime.class, new FooRuntimeTypeAdapter());
Gson gson = builder.create();
Foo foo = gson.fromJson(input, Foo.class);
빠르고 쉬운 회피책 - 런타임의 멤버 유형 필드를 String으로 변경하고 int로 runtime을 반환하는 getter를 통해 액세스합니다.
public class Foo
{
private String name;
private String runtime;
public int getRuntime(){
if(runtime == null || runtime.equals("")){
return 0;
}
return Integer.valueOf(trackId);
}
}
=> json 역직렬화 불필요
빈 문자열이 있는지 확인하고 0을 반환하는 이 타입 어댑터를 만들었습니다.
public class IntegerTypeAdapter extends TypeAdapter<Number> {
@Override
public void write(JsonWriter jsonWriter, Number number) throws IOException {
if (number == null) {
jsonWriter.nullValue();
return;
}
jsonWriter.value(number);
}
@Override
public Number read(JsonReader jsonReader) throws IOException {
if (jsonReader.peek() == JsonToken.NULL) {
jsonReader.nextNull();
return null;
}
try {
String value = jsonReader.nextString();
if ("".equals(value)) {
return 0;
}
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
}
다른 코멘트에 기재되어 있듯이 GSON 2.3.1에서는 원시 타입의 타입 어댑터를 등록할 수 있습니다.여기에서는 int 타입과 Integer 타입을 처리하는 타입 어댑터를 사용할 수 있습니다.문자열, 부울 및 늘의 경우 디폴트값이 0(또는 늘)으로 되어 있습니다.그러면 "runtime" : "5"와 같은 숫자가 포함된 문자열이 계속 해석됩니다.
public static final TypeAdapter<Number> UNRELIABLE_INTEGER = new TypeAdapter<Number>() {
@Override
public Number read(JsonReader in) throws IOException {
JsonToken jsonToken = in.peek();
switch (jsonToken) {
case NUMBER:
case STRING:
String s = in.nextString();
try {
return Integer.parseInt(s);
} catch (NumberFormatException ignored) {
}
try {
return (int)Double.parseDouble(s);
} catch (NumberFormatException ignored) {
}
return null;
case NULL:
in.nextNull();
return null;
case BOOLEAN:
in.nextBoolean();
return null;
default:
throw new JsonSyntaxException("Expecting number, got: " + jsonToken);
}
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
out.value(value);
}
};
public static final TypeAdapterFactory UNRELIABLE_INTEGER_FACTORY = TypeAdapters.newFactory(int.class, Integer.class, UNRELIABLE_INTEGER);
다음 코드로 등록할 수 있습니다.
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(UNRELIABLE_INTEGER_FACTORY)
.create();
이것이 콜 해석의 시행을 대체하는 통상의 JsonReader.nextInt()에 주의해 주세요.토큰의 Int 및 parseDouble을 사용하면 정수를 해석하기 위한 내부 로직이 복제됩니다.
이 될 수 있습니다.0
★★★runtime
Format Exception이이 될 수 에 에는 Format Exception을 합니다.[ Format Exception ( Format Exception ) ] format 、 [ Format Exception ]를 선택합니다.
이 솔루션은 Double type에서 작동합니다.이것은 비 프라이머리 타입에 대해서만 동작합니다.
public class DoubleGsonTypeAdapter implements JsonDeserializer<Double> {
@Override
public Double deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
Double result = null;
try {
result = jsonElement.getAsDouble();
} catch (NumberFormatException e) {
return result;
}
return result;
}
}
모델:
@SerializedName("rateOfInterest")
public Double rateOfInterest;
@SerializedName("repaymentTenure")
public Double repaymentTenure;
@SerializedName("emiAmount")
public Double emiAmount;
개조 클라이언트:
Gson gson = new GsonBuilder().registerTypeAdapter(Double.class, new DoubleGsonTypeAdapter()) .create();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
어댑터 없음
수 없이 forgive forgive forgive 、 forgive 、 forgive 、 forgive 、 forgive 、 forgive 、 forgive 、 forgive 、 forgive forgive , forgive forgive forgive forgive forgive 、 forgive forgive forgive forgive forgive forgive forgive forgive forgive forgive forgive forgive forgive forgive forgive Model Class
to " " " 。String
예를 들어 나는 가지고 있었다.
data class Info(
@SerializedName("name") val name : String?,
@SerializedName("cover") val cover : String?,
@SerializedName("releaseDate") val releaseDate : Int?,
@SerializedName("last_modified") val last_modified : Int?,
@SerializedName("rating") val rating : Int?)
나는 숫자와 마주하고 있었다.Format Exception으로 변경했습니다.
data class Info(
@SerializedName("name") val name : String?,
@SerializedName("cover") val cover : String?,
@SerializedName("releaseDate") val releaseDate : String?,
@SerializedName("last_modified") val last_modified : String?,
@SerializedName("rating") val rating : String?)
이제 확인해보겠습니다.
if(!TextUtils.isEmpty(releaseDate){
//go ahead to use it
}
언급URL : https://stackoverflow.com/questions/8863429/how-to-handle-a-numberformatexception-with-gson-in-deserialization-a-json-respon
'programing' 카테고리의 다른 글
스프링 부트 앱에서 스프링 보안 비활성화 (0) | 2023.03.13 |
---|---|
redux 툴킷을 사용할 때 "상태에서 직렬화할 수 없는 값이 검출되었습니다"라는 오류가 표시되지만 일반 redux에서는 검출되지 않습니다. (0) | 2023.03.13 |
angularjs가 포함된 두 개의 중첩 클릭 이벤트 (0) | 2023.03.13 |
Angular Routed 컴포넌트에 데이터를 전달하려면 어떻게 해야 합니까? (0) | 2023.03.13 |
woocommerce 체크아웃 페이지에 업데이트된 데이터 표시 (0) | 2023.03.13 |