Gson 옵션 및 필수 필드
하면 좋을까요?Gson
필수필드와 옵션필드의 비교
되어 있는지 여부에 네트워크 할 수 Gson
무효
하고 방법gson.fromJson(json, mClassOfT);
예를 들어 다음과 같은 json이 있는 경우:
{"user_id":128591, "user_name":"TestUser"}
그리고 우리 반:
public class User {
@SerializedName("user_id")
private String mId;
@SerializedName("user_name")
private String mName;
public String getId() {
return mId;
}
public void setId(String id) {
mId = id;
}
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
}
}
「」를 취득하기 입니까?Gson
이 json을 하지 않으면 합니다.user_id
★★★★★★★★★★★★★★★★★」user_name
열쇠요?
구문 분석해야 할 값 중 하나와 옵션 값 중 하나가 필요한 경우가 많습니다.
이 사건을 글로벌하게 처리하기 위해 사용할 패턴이나 라이브러리가 있습니까?
감사해요.
필드 ' 필드'만 표시됩니다.null
된 항목이 있는 합니다.
이를 위해 재사용 가능한 역직렬라이저와 주석을 소개합니다.가 현재에서의 커스텀 로 하는 더 POJO를 입니다.Gson
오브젝트 자체로의 역직렬화 또는 주석 체크 아웃을 다른 메서드로 이동하여 역직렬화에서 사용합니다., 해, 「 처리」에으로, .JsonParseException
할 수 하기 위해, 을 통해 검출할 수 있습니다.getCause()
를 참조해 주세요.
이 모든 것이, 대부분의 경우, 이것은 유효합니다.
public class App
{
public static void main(String[] args)
{
Gson gson =
new GsonBuilder()
.registerTypeAdapter(TestAnnotationBean.class, new AnnotatedDeserializer<TestAnnotationBean>())
.create();
String json = "{\"foo\":\"This is foo\",\"bar\":\"this is bar\"}";
TestAnnotationBean tab = gson.fromJson(json, TestAnnotationBean.class);
System.out.println(tab.foo);
System.out.println(tab.bar);
json = "{\"foo\":\"This is foo\"}";
tab = gson.fromJson(json, TestAnnotationBean.class);
System.out.println(tab.foo);
System.out.println(tab.bar);
json = "{\"bar\":\"This is bar\"}";
tab = gson.fromJson(json, TestAnnotationBean.class);
System.out.println(tab.foo);
System.out.println(tab.bar);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface JsonRequired
{
}
class TestAnnotationBean
{
@JsonRequired public String foo;
public String bar;
}
class AnnotatedDeserializer<T> implements JsonDeserializer<T>
{
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
{
T pojo = new Gson().fromJson(je, type);
Field[] fields = pojo.getClass().getDeclaredFields();
for (Field f : fields)
{
if (f.getAnnotation(JsonRequired.class) != null)
{
try
{
f.setAccessible(true);
if (f.get(pojo) == null)
{
throw new JsonParseException("Missing field in JSON: " + f.getName());
}
}
catch (IllegalArgumentException ex)
{
Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IllegalAccessException ex)
{
Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
return pojo;
}
}
출력:
이것은 foo입니다.여기는 술집입니다이것은 foo입니다.무효"main" 스레드 com.google.gson에 예외가 있습니다.JsonParse Exception:JSON에서 누락된 필드: foo
Brian Roach의 답변은 매우 좋지만, 때로는 다음과 같은 사항을 다루어야 합니다.
- 모델의 슈퍼 클래스 특성
- 어레이 내부의 속성
이러한 목적을 위해 다음 클래스를 사용할 수 있습니다.
/**
* Adds the feature to use required fields in models.
*
* @param <T> Model to parse to.
*/
public class JsonDeserializerWithOptions<T> implements JsonDeserializer<T> {
/**
* To mark required fields of the model:
* json parsing will be failed if these fields won't be provided.
* */
@Retention(RetentionPolicy.RUNTIME) // to make reading of this field possible at the runtime
@Target(ElementType.FIELD) // to make annotation accessible through reflection
public @interface FieldRequired {}
/**
* Called when the model is being parsed.
*
* @param je Source json string.
* @param type Object's model.
* @param jdc Unused in this case.
*
* @return Parsed object.
*
* @throws JsonParseException When parsing is impossible.
* */
@Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException {
// Parsing object as usual.
T pojo = new Gson().fromJson(je, type);
// Getting all fields of the class and checking if all required ones were provided.
checkRequiredFields(pojo.getClass().getDeclaredFields(), pojo);
// Checking if all required fields of parent classes were provided.
checkSuperClasses(pojo);
// All checks are ok.
return pojo;
}
/**
* Checks whether all required fields were provided in the class.
*
* @param fields Fields to be checked.
* @param pojo Instance to check fields in.
*
* @throws JsonParseException When some required field was not met.
* */
private void checkRequiredFields(@NonNull Field[] fields, @NonNull Object pojo)
throws JsonParseException {
// Checking nested list items too.
if (pojo instanceof List) {
final List pojoList = (List) pojo;
for (final Object pojoListPojo : pojoList) {
checkRequiredFields(pojoListPojo.getClass().getDeclaredFields(), pojoListPojo);
checkSuperClasses(pojoListPojo);
}
}
for (Field f : fields) {
// If some field has required annotation.
if (f.getAnnotation(FieldRequired.class) != null) {
try {
// Trying to read this field's value and check that it truly has value.
f.setAccessible(true);
Object fieldObject = f.get(pojo);
if (fieldObject == null) {
// Required value is null - throwing error.
throw new JsonParseException(String.format("%1$s -> %2$s",
pojo.getClass().getSimpleName(),
f.getName()));
} else {
checkRequiredFields(fieldObject.getClass().getDeclaredFields(), fieldObject);
checkSuperClasses(fieldObject);
}
}
// Exceptions while reflection.
catch (IllegalArgumentException | IllegalAccessException e) {
throw new JsonParseException(e);
}
}
}
}
/**
* Checks whether all super classes have all required fields.
*
* @param pojo Object to check required fields in its superclasses.
*
* @throws JsonParseException When some required field was not met.
* */
private void checkSuperClasses(@NonNull Object pojo) throws JsonParseException {
Class<?> superclass = pojo.getClass();
while ((superclass = superclass.getSuperclass()) != null) {
checkRequiredFields(superclass.getDeclaredFields(), pojo);
}
}
}
우선 필수 필드를 마킹하기 위한 인터페이스(주석)에 대해 설명합니다.이 사용 예에 대해서는 나중에 설명하겠습니다.
/**
* To mark required fields of the model:
* json parsing will be failed if these fields won't be provided.
* */
@Retention(RetentionPolicy.RUNTIME) // to make reading of this field possible at the runtime
@Target(ElementType.FIELD) // to make annotation accessible throw the reflection
public @interface FieldRequired {}
★★★★★★★★★★★★★★★.deserialize
메서드가 구현됩니다.평소와 즉, 결과 이 누락되어 있습니다. 결과에서 속성이 누락됨pojo
가지다null
§:
T pojo = new Gson().fromJson(je, type);
다음 구문 체크합니다.pojo
기동합니다.
checkRequiredFields(pojo.getClass().getDeclaredFields(), pojo);
다음, '있다'의 .pojo
의 슈퍼클래스:
checkSuperClasses(pojo);
경우에 어떤 경우에 따라서는요.SimpleModel
its를 SimpleParentModel
성질을 .SimpleModel
에 따라 가 붙어 있는 경우는, 「필요한 경우」라고 됩니다.SimpleParentModel
의 것입니다.
그럼 한번 요?checkRequiredFields
이 '재산이 있다'의 인스턴스인지 아닌지를 확인합니다.List
(array) - 이 하여 모든 (json array) - 필수 필드입니다.
if (pojo instanceof List) {
final List pojoList = (List) pojo;
for (final Object pojoListPojo : pojoList) {
checkRequiredFields(pojoListPojo.getClass().getDeclaredFields(), pojoListPojo);
checkSuperClasses(pojoListPojo);
}
}
.pojo
에 모음음음음음 , , 、 나 with with with with with with 。FieldRequired
이이이.무효로컬 속속속 속속외예예예예예예예예예예예예다다다다다다.그렇지 않으면 현재 필드에 대해 다른 재귀적 검증 단계가 시작되고 필드의 상위 클래스 속성도 검사됩니다.
for (Field f : fields) {
// If some field has required annotation.
if (f.getAnnotation(FieldRequired.class) != null) {
try {
// Trying to read this field's value and check that it truly has value.
f.setAccessible(true);
Object fieldObject = f.get(pojo);
if (fieldObject == null) {
// Required value is null - throwing error.
throw new JsonParseException(String.format("%1$s -> %2$s",
pojo.getClass().getSimpleName(),
f.getName()));
} else {
checkRequiredFields(fieldObject.getClass().getDeclaredFields(), fieldObject);
checkSuperClasses(fieldObject);
}
}
// Exceptions while reflection.
catch (IllegalArgumentException | IllegalAccessException e) {
throw new JsonParseException(e);
}
}
}
마지막 은 검토해야 .checkSuperClasses
: 필수 pojo
의 슈퍼클래스:
Class<?> superclass = pojo.getClass();
while ((superclass = superclass.getSuperclass()) != null) {
checkRequiredFields(superclass.getDeclaredFields(), pojo);
}
.JsonDeserializerWithOptions
다음과 합니다.하다
private class SimpleModel extends SimpleParentModel {
@JsonDeserializerWithOptions.FieldRequired Long id;
@JsonDeserializerWithOptions.FieldRequired NestedModel nested;
@JsonDeserializerWithOptions.FieldRequired ArrayList<ListModel> list;
}
private class SimpleParentModel {
@JsonDeserializerWithOptions.FieldRequired Integer rev;
}
private class NestedModel extends NestedParentModel {
@JsonDeserializerWithOptions.FieldRequired Long id;
}
private class NestedParentModel {
@JsonDeserializerWithOptions.FieldRequired Integer rev;
}
private class ListModel {
@JsonDeserializerWithOptions.FieldRequired Long id;
}
알 수 .SimpleModel
예외 분석됩니다.
final Gson gson = new GsonBuilder()
.registerTypeAdapter(SimpleModel.class, new JsonDeserializerWithOptions<SimpleModel>())
.create();
gson.fromJson("{\"list\":[ { \"id\":1 } ], \"id\":1, \"rev\":22, \"nested\": { \"id\":2, \"rev\":2 }}", SimpleModel.class);
많은 기능을 할 수 . 예를 "은 "네스트된 오브젝트"로 . 예를 들어, 네스트된 객체에 대한 검증은 다음과 같습니다.FieldRequired
수 없지만 할 수 요.현재는 답변 범위를 벗어났지만 나중에 추가할 수 있습니다.
이것은 최소한의 코딩으로 범용 솔루션을 작성하는 간단한 솔루션입니다.
- Create @옵션 주석
- 첫 번째 옵션 표시.나머지는 선택 사항으로 간주됩니다.더 이른 시간이 필요한 것으로 가정합니다.
- 소스 Json 개체에 값이 있는지 확인하는 일반 '로더' 메서드를 만듭니다.@Optional 필드가 발생하면 루프가 정지합니다.
저는 서브클래스를 사용하고 있기 때문에 그른트 작업은 슈퍼클래스로 진행됩니다.
여기 슈퍼클래스 코드가 있습니다.
import com.google.gson.Gson;
import java.lang.reflect.Field;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
...
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Optional {
public boolean enabled() default true;
}
그리고 grunt 작업 방법
@SuppressWarnings ("unchecked")
public <T> T payload(JsonObject oJR,Class<T> T) throws Exception {
StringBuilder oSB = new StringBuilder();
String sSep = "";
Object o = gson.fromJson(oJR,T);
// Ensure all fields are populated until we reach @Optional
Field[] oFlds = T.getDeclaredFields();
for(Field oFld:oFlds) {
Annotation oAnno = oFld.getAnnotation(Optional.class);
if (oAnno != null) break;
if (!oJR.has(oFld.getName())) {
oSB.append(sSep+oFld.getName());
sSep = ",";
}
}
if (oSB.length() > 0) throw CVT.e("Required fields "+oSB+" mising");
return (T)o;
}
사용 예
public static class Payload {
String sUserType ;
String sUserID ;
String sSecpw ;
@Optional
String sUserDev ;
String sUserMark ;
}
입력 코드
Payload oPL = payload(oJR,Payload.class);
이 경우 sUserDev 및 sUserMark는 옵션이며 나머지는 필수입니다.솔루션은 클래스가 필드 정의를 선언된 순서대로 저장한다는 사실에 의존합니다.
많이 찾아봤지만 좋은 답이 없어요.제가 선택한 솔루션은 다음과 같습니다.
JSON에서 설정해야 하는 모든 필드는 개체입니다(예: 상자 안의 정수, 부울 등).그런 다음 리플렉션을 사용하여 필드가 null이 아님을 확인할 수 있습니다.
public class CJSONSerializable {
public void checkDeserialization() throws IllegalAccessException, JsonParseException {
for (Field f : getClass().getDeclaredFields()) {
if (f.get(this) == null) {
throw new JsonParseException("Field " + f.getName() + " was not initialized.");
}
}
}
}
이 클래스에서 JSON 객체를 도출할 수 있습니다.
public class CJSONResp extends CJSONSerializable {
@SerializedName("Status")
public String status;
@SerializedName("Content-Type")
public String contentType;
}
그런 다음 GSON을 사용하여 해석한 후 checkDeserialization을 호출하면 일부 필드가 null일 경우 보고됩니다.
(Brian Roache의 대답에서 영감을 얻었다.)
null이 다른 될 수 Brian의 가 없는 것 "null" "null" "Brian" "Brian" "Brian" "Brian" "Brian" "Brian" "Brian" "Brian" "Brian" "Brian" "Brian" ( "Brian "Brian")0
를 참조해 주세요.
게다가 탈직렬기는 모든 타입에 등록해야 할 것 같습니다.에서는 「」를 합니다.TypeAdapterFactory
(일부러)
로 하는 이 더 를 들어, 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 등).JsonOptional
필요한 경우 모든 필드에 주석을 달지 않고 필드)를 선택합니다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonOptional {
}
이 접근방식은 대신 필수 분야에 쉽게 적용할 수 있습니다.
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class AnnotatedTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Class<? super T> rawType = typeToken.getRawType();
Set<Field> requiredFields = Stream.of(rawType.getDeclaredFields())
.filter(f -> f.getAnnotation(JsonOptional.class) == null)
.collect(Collectors.toSet());
if (requiredFields.isEmpty()) {
return null;
}
final TypeAdapter<T> baseAdapter = (TypeAdapter<T>) gson.getAdapter(rawType);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter jsonWriter, T o) throws IOException {
baseAdapter.write(jsonWriter, o);
}
@Override
public T read(JsonReader in) throws IOException {
JsonElement jsonElement = Streams.parse(in);
if (jsonElement.isJsonObject()) {
ArrayList<String> missingFields = new ArrayList<>();
for (Field field : requiredFields) {
if (!jsonElement.getAsJsonObject().has(field.getName())) {
missingFields.add(field.getName());
}
}
if (!missingFields.isEmpty()) {
throw new JsonParseException(
String.format("Missing required fields %s for %s",
missingFields, rawType.getName()));
}
}
TypeAdapter<T> delegate = gson.getDelegateAdapter(AnnotatedTypeAdapterFactory.this, typeToken);
return delegate.fromJsonTree(jsonElement);
}
};
}
}
언급URL : https://stackoverflow.com/questions/21626690/gson-optional-and-required-fields
'programing' 카테고리의 다른 글
TypeScript의 개체 리터럴에 정의를 입력합니다. (0) | 2023.03.06 |
---|---|
React에서 JSON 파일 가져오기 (0) | 2023.03.06 |
사용자 정의 Angular에 '바꾸기' 기능을 사용하는 방법JS 디렉티브? (0) | 2023.03.06 |
Angular 2의 http.get()을 사용하여 로컬 파일에서 JSON 콘텐츠를 로드합니다. (0) | 2023.03.06 |
사용자 정의된 플러그인의 wordpress admin에 페이지 번호 추가 (0) | 2023.03.06 |