Gson: Jak wykluczyć określone pola z serializacji bez adnotacji

413

Próbuję nauczyć się Gsona i walczę o wykluczenie z pola. Oto moje zajęcia

public class Student {    
  private Long                id;
  private String              firstName        = "Philip";
  private String              middleName       = "J.";
  private String              initials         = "P.F";
  private String              lastName         = "Fry";
  private Country             country;
  private Country             countryOfBirth;
}

public class Country {    
  private Long                id;
  private String              name;
  private Object              other;
}

Mogę użyć GsonBuilder i dodać ExclusionStrategy dla nazwy pola jak firstNamelub, countryale wydaje mi się, że nie jestem w stanie wykluczyć właściwości niektórych pól takich jak country.name.

Przy użyciu tej metody public boolean shouldSkipField(FieldAttributes fa)FieldAttributes nie zawiera wystarczającej ilości informacji, aby dopasować pole do filtru podobnego do country.name.

PS: Chcę uniknąć adnotacji, ponieważ chcę to poprawić i użyć RegEx do odfiltrowania pól.

Edycja : Próbuję sprawdzić, czy można emulować zachowanie wtyczki Struts2 JSON

za pomocą Gson

<interceptor-ref name="json">
  <param name="enableSMD">true</param>
  <param name="excludeProperties">
    login.password,
    studentList.*\.sin
  </param>
</interceptor-ref>

Edycja: Ponownie otworzyłem pytanie z następującym dodatkiem:

Dodałem drugie pole tego samego typu, aby później wyjaśnić ten problem. Zasadniczo chcę wykluczyć, country.nameale nie countrOfBirth.name. Nie chcę również wykluczać kraju jako typu. Więc typy są takie same, to faktyczne miejsce na wykresie obiektowym, które chcę wskazać i wykluczyć.

Liviu T.
źródło
1
Nadal od wersji 2.2 nadal nie mogę określić ścieżki do pola do wykluczenia. flexjson.sourceforge.net wydaje się dobrą alternatywą.
Liviu T.,
Zobacz moją odpowiedź na dość podobne pytanie. Polega na stworzeniu niestandardowego JsonSerializerdla jakiegoś typu - Countryw twoim przypadku - dla którego następnie jest stosowany i ExclusionStrategyktóry decyduje, które pola serializować.
pirho

Odpowiedzi:

625

Wszelkie pola, których generalnie nie chcesz serializować, powinieneś użyć modyfikatora „przejściowego”, a dotyczy to także serializatorów json (przynajmniej dotyczy kilku, których użyłem, w tym gson).

Jeśli nie chcesz, aby nazwa pojawiała się w serializowanym pliku Json, podaj mu przejściowe słowo kluczowe, np .:

private transient String name;

Więcej szczegółów w dokumentacji Gson

Chris Seline
źródło
6
jest to prawie to samo, co adnotacja wykluczająca, jak w przypadku wszystkich instancji tej klasy. Chciałem dynamicznego wykluczenia środowiska wykonawczego. W niektórych przypadkach chcę, aby niektóre pola zostały wykluczone w celu zapewnienia jaśniejszej / ograniczonej odpowiedzi, aw innych chcę serializować pełny obiekt
Liviu T.
34
Należy zwrócić uwagę na to, że efekty przejściowe powodują zarówno serializację, jak i deserializację. Wyemituje również wartość z serializacji do obiektu, nawet jeśli jest on obecny w JSON.
Kong
3
Problem z używaniem transientzamiast tego @Exposepolega na tym, że nadal musisz wykpić POJO na swoim kliencie ze wszystkimi polami, które mogą się pojawić. W przypadku interfejsu API zaplecza, który może być współdzielony między projektami, może to być problematyczne w przypadku dodatkowe pola są dodawane. Zasadniczo jest to biała lista vs. czarna lista pól.
theblang
11
To podejście nie działało dla mnie, ponieważ nie tylko wykluczyło pole z serializacji gson, ale wykluczyło pole z wewnętrznej serializacji aplikacji (przy użyciu interfejsu Serializable).
pkk
8
transient zapobiega SERIALIZACJI i DESERIALIZACJI pola. To nie odpowiada moim potrzebom.
Loenix,
318

Nishant zapewnił dobre rozwiązanie, ale istnieje prostszy sposób. Po prostu zaznacz wybrane pola adnotacją @Expose, na przykład:

@Expose private Long id;

Pomiń wszystkie pola, których nie chcesz serializować. Następnie po prostu utwórz obiekt Gson w ten sposób:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
JayPea
źródło
95
Czy można mieć coś takiego jak „nieeksponuj” i zignorować je tylko w przypadku, gdy wszystkie oprócz jednego pola muszą być serializowane, a dodawanie adnotacji do wszystkich z nich jest zbędne?
Daniil Shevelev
2
@ DaSh Ostatnio miałem taki scenariusz. Bardzo łatwo było napisać niestandardową strategię wykluczenia, która właśnie to zrobiła. Zobacz odpowiedź Nishanta. Jedynym problemem było włączenie kilku klas kontenerów i skrzypce z skipclass vs. skipfield (pola mogą być klasami ...)
keyser
1
@DaSh Moja odpowiedź poniżej dokładnie to robi.
Derek Shockey
Co za świetne rozwiązanie. Natrafiłem na scenariusz, w którym chcę, aby pole zostało zserializowane na dysk, ale zostanie zignorowane podczas wysyłania go do serwera przez gson. Perfekcyjnie, dzięki!
Slynk
1
@Danlil Powinieneś być w stanie użyć @Expose (serialize = false, deserialize = false)
Hrk
237

Więc chcesz wykluczyć firstName i country.name. Oto jak ExclusionStrategypowinieneś wyglądać

    public class TestExclStrat implements ExclusionStrategy {

        public boolean shouldSkipClass(Class<?> arg0) {
            return false;
        }

        public boolean shouldSkipField(FieldAttributes f) {

            return (f.getDeclaringClass() == Student.class && f.getName().equals("firstName"))||
            (f.getDeclaringClass() == Country.class && f.getName().equals("name"));
        }

    }

Jeśli przyjrzysz się uważnie, wróci truedo Student.firstNamei Country.name, co chcesz wykluczyć.

Musisz zastosować to w ExclusionStrategyten sposób,

    Gson gson = new GsonBuilder()
        .setExclusionStrategies(new TestExclStrat())
        //.serializeNulls() <-- uncomment to serialize NULL fields as well
        .create();
    Student src = new Student();
    String json = gson.toJson(src);
    System.out.println(json);

Zwraca to:

{ "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91}}

Zakładam, że obiekt wiejski jest inicjowany id = 91Lw klasie studenckiej.


Możesz mieć ochotę. Na przykład nie chcesz serializować żadnego pola zawierającego ciąg „nazwa” w jego nazwie. Zrób to:

public boolean shouldSkipField(FieldAttributes f) {
    return f.getName().toLowerCase().contains("name"); 
}

Zwróci to:

{ "initials": "P.F", "country": { "id": 91 }}

EDYCJA: Dodano więcej informacji zgodnie z żądaniem.

To ExclusionStrategywystarczy, ale musisz przekazać „W pełni kwalifikowana nazwa pola”. Patrz poniżej:

    public class TestExclStrat implements ExclusionStrategy {

        private Class<?> c;
        private String fieldName;
        public TestExclStrat(String fqfn) throws SecurityException, NoSuchFieldException, ClassNotFoundException
        {
            this.c = Class.forName(fqfn.substring(0, fqfn.lastIndexOf(".")));
            this.fieldName = fqfn.substring(fqfn.lastIndexOf(".")+1);
        }
        public boolean shouldSkipClass(Class<?> arg0) {
            return false;
        }

        public boolean shouldSkipField(FieldAttributes f) {

            return (f.getDeclaringClass() == c && f.getName().equals(fieldName));
        }

    }

Oto, w jaki sposób możemy go ogólnie użyć.

    Gson gson = new GsonBuilder()
        .setExclusionStrategies(new TestExclStrat("in.naishe.test.Country.name"))
        //.serializeNulls()
        .create();
    Student src = new Student();
    String json = gson.toJson(src);
    System.out.println(json); 

Zwraca:

{ "firstName": "Philip" , "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91 }}
Nishant
źródło
Dziękuję za odpowiedź. Chcę stworzyć ExclusionStrategy, która może przyjmować ciąg znaków country.namei wykluczać pole tylko namepodczas serializacji pola country. Powinien być na tyle ogólny, aby dotyczyć każdej klasy, która ma właściwość o nazwie kraj klasy Country. Nie chcę tworzyć strategii wykluczania dla każdej klasy
Liviu T.
@Liviu T. Zaktualizowałem odpowiedź. To wymaga ogólnego podejścia. Możesz stać się jeszcze bardziej kreatywny, ale zachowałem to jako elementarne.
Nishant
Ty za aktualizację. To, co próbuję zobaczyć, czy można wiedzieć, gdzie na wykresie obiektowym jestem, gdy metoda, którą wywołała, dzięki czemu mogę wykluczyć niektóre pola kraju, ale nie countryOfBirth (na przykład), a więc tę samą klasę, ale inne właściwości. Zredagowałem swoje pytanie, aby wyjaśnić, co próbuję osiągnąć
Liviu T.
Czy istnieje sposób na wykluczenie pól, które mają puste wartości?
Yusuf K.,
12
Ta odpowiedź powinna być oznaczona jako odpowiedź preferowana. W przeciwieństwie do innych odpowiedzi, które mają obecnie więcej głosów, to rozwiązanie nie wymaga modyfikacji klasy fasoli. To ogromny plus. Co jeśli ktoś inny używałby tej samej klasy fasoli, a ty zaznaczyłeś pole, które chciał, aby trwało jako „przejściowe”?
user64141
221

Po przeczytaniu wszystkich dostępnych odpowiedzi odkryłem, że najbardziej elastycznym, w moim przypadku, było użycie niestandardowej @Excludeadnotacji. W związku z tym wdrożyłem prostą strategię (nie chciałem oznaczać wszystkich pól za pomocą, @Exposeani nie chciałem używać, transientktóre były w konflikcie przy Serializableserializacji aplikacji ):

Adnotacja:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Exclude {
}

Strategia:

public class AnnotationExclusionStrategy implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Exclude.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}

Stosowanie:

new GsonBuilder().setExclusionStrategies(new AnnotationExclusionStrategy()).create();
pkk
źródło
16
Jako dodatkową uwagę, jeśli chcesz użyć swojej strategii wykluczania tylko do serializacji lub tylko deserializacji, użyj: addSerializationExclusionStrategylub addDeserializationExclusionStrategyzamiastsetExclusionStrategies
GLee
9
Doskonały! Rozwiązanie przejściowe nie działa dla mnie, ponieważ używam Realm dla DB i chcę wykluczyć pole tylko z Gson, ale nie Realm (co przejściowe działa)
Marcio Granzotto
3
To powinna być zaakceptowana odpowiedź. Aby zignorować puste pola, zmień f.getAnnotation(Exclude.class) != nullnaf.getAnnotation(Exclude.class) == null
Sharp Edge
3
Znakomity, gdy nie możesz korzystać z transientpowodu potrzeb innych bibliotek. Dzięki!
Martin D
1
Świetnie też dla mnie, ponieważ Android szereguje moje klasy między zajęciami, ale chcę, aby były one wyłączone, gdy używam GSON. Dzięki temu moja aplikacja działa tak samo, dopóki nie chce ich zawinąć i wysłać do innych.
ThePartyTurtle
81

Natknąłem się na ten problem, w którym miałem niewielką liczbę pól, które chciałem wykluczyć tylko z serializacji, więc opracowałem dość proste rozwiązanie, które wykorzystuje @Exposeadnotację Gsona z niestandardowymi strategiami wykluczania.

Jedynym wbudowanym sposobem użycia @Exposejest ustawienie GsonBuilder.excludeFieldsWithoutExposeAnnotation(), ale jak wskazuje nazwa, pola bez wyraźnego tekstu @Exposesą ignorowane. Ponieważ miałem tylko kilka pól, które chciałem wykluczyć, perspektywa dodania adnotacji do każdego pola była bardzo kłopotliwa.

Skutecznie chciałem mieć odwrotność, w której wszystko było zawarte, chyba że wyraźnie @Exposeto wykluczyłem. W tym celu zastosowałem następujące strategie wykluczania:

new GsonBuilder()
        .addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                final Expose expose = fieldAttributes.getAnnotation(Expose.class);
                return expose != null && !expose.serialize();
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                return false;
            }
        })
        .addDeserializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                final Expose expose = fieldAttributes.getAnnotation(Expose.class);
                return expose != null && !expose.deserialize();
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                return false;
            }
        })
        .create();

Teraz mogę łatwo wykluczyć kilka pól z @Expose(serialize = false)lub @Expose(deserialize = false)adnotacjami (zwróć uwagę, że domyślną wartością dla obu @Exposeatrybutów jest true). Możesz oczywiście użyć @Expose(serialize = false, deserialize = false), ale jest to bardziej zwięzłe, zadeklarując pole transientzamiast tego (co nadal obowiązuje w przypadku tych niestandardowych strategii wykluczania).

Derek Shockey
źródło
Dla zwiększenia wydajności widzę przypadek użycia @Expose (serialize = false, deserialize = false) zamiast przejściowego.
paiego
1
@paiego Czy możesz to rozwinąć? Mam wiele lat od używania Gsona i nie rozumiem, dlaczego adnotacja jest bardziej wydajna niż oznaczanie jej jako przejściowej.
Derek Shockey
Achh, popełniłem błąd, dziękuję za złapanie tego. Pomyliłem zmienność z przemijającą. (np. Nie ma buforowania, a zatem nie występuje problem ze spójnością pamięci podręcznej z niestabilnymi, ale jest mniej wydajny) W każdym razie twój kod działał świetnie!
paiego,
18

Możesz eksplorować drzewo Json za pomocą gson.

Wypróbuj coś takiego:

gson.toJsonTree(student).getAsJsonObject()
.get("country").getAsJsonObject().remove("name");

Możesz także dodać niektóre właściwości:

gson.toJsonTree(student).getAsJsonObject().addProperty("isGoodStudent", false);

Testowane z gson 2.2.4.

Klaudia Rzewnicka
źródło
3
Zastanawiam się, czy jest to zbyt duży spadek wydajności, jeśli chcesz pozbyć się złożonej właściwości, którą należy przeanalizować przed usunięciem. Myśli?
Ben,
Zdecydowanie nie jest to skalowalne rozwiązanie, wyobraź sobie ból głowy, który musisz przejść, jeśli zmienisz strukturę obiektu lub dodasz / usuniesz rzeczy.
codenamezero
16

Wymyśliłem fabrykę klas, która wspiera tę funkcjonalność. Przekaż dowolną kombinację pól lub klas, które chcesz wykluczyć.

public class GsonFactory {

    public static Gson build(final List<String> fieldExclusions, final List<Class<?>> classExclusions) {
        GsonBuilder b = new GsonBuilder();
        b.addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return fieldExclusions == null ? false : fieldExclusions.contains(f.getName());
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return classExclusions == null ? false : classExclusions.contains(clazz);
            }
        });
        return b.create();

    }
}

Aby użyć, utwórz dwie listy (każda jest opcjonalna) i utwórz obiekt GSON:

static {
 List<String> fieldExclusions = new ArrayList<String>();
 fieldExclusions.add("id");
 fieldExclusions.add("provider");
 fieldExclusions.add("products");

 List<Class<?>> classExclusions = new ArrayList<Class<?>>();
 classExclusions.add(Product.class);
 GSON = GsonFactory.build(null, classExclusions);
}

private static final Gson GSON;

public String getSomeJson(){
    List<Provider> list = getEntitiesFromDatabase();
    return GSON.toJson(list);
}
Domenic D.
źródło
Oczywiście można to zmienić, aby spojrzeć na w pełni kwalifikowaną nazwę atrybutu i wykluczyć ją podczas meczu ...
Domenic D.
Robię poniżej przykład. To nie działa. Pls sugerują prywatny statyczny finał Gson GSON; static {List <String> fieldExclusion = new ArrayList <String> (); fieldExclusion.add („id”); GSON = GsonFactory.build (fieldExclusion, null); } prywatny statyczny Ciąg getSomeJson () {String jsonStr = "[{\" id \ ": 111, \" name \ ": \" praveen \ ", \" age \ ": 16}, {\" id \ ": 222, \ "name \": \ "prashant \", \ "age \": 20}] "; return jsonStr; } public static void main (String [] args) {String jsonStr = getSomeJson (); System.out.println (GSON.toJson (jsonStr)); }
Praveen Hiremath,
13

Rozwiązałem ten problem za pomocą niestandardowych adnotacji. To jest moja klasa adnotacji „SkipSerialisation”:

@Target (ElementType.FIELD)
public @interface SkipSerialisation {

}

i to jest mój GsonBuilder:

gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {

  @Override public boolean shouldSkipField (FieldAttributes f) {

    return f.getAnnotation(SkipSerialisation.class) != null;

  }

  @Override public boolean shouldSkipClass (Class<?> clazz) {

    return false;
  }
});

Przykład:

public class User implements Serializable {

  public String firstName;

  public String lastName;

  @SkipSerialisation
  public String email;
}
Hibbem
źródło
5
Gson: Jak wykluczyć określone pola z serializacji bez adnotacji
Ben
3
Powinieneś również dodać @Retention(RetentionPolicy.RUNTIME)do swojej adnotacji.
David Novák,
9

Lub może powiedzieć, jakie pola nie zostaną ujawnione za pomocą:

Gson gson = gsonBuilder.excludeFieldsWithModifiers(Modifier.TRANSIENT).create();

w twojej klasie na atrybucie:

private **transient** boolean nameAttribute;
lucasddaniel
źródło
17
Pola przejściowe i statyczne są domyślnie wyłączone; nie ma potrzeby do tego dzwonić excludeFieldsWithModifiers().
Derek Shockey
9

Użyłem tej strategii: wykluczyłem wszystkie pola, które nie są oznaczone adnotacją @SerializedName , tj .:

public class Dummy {

    @SerializedName("VisibleValue")
    final String visibleValue;
    final String hiddenValue;

    public Dummy(String visibleValue, String hiddenValue) {
        this.visibleValue = visibleValue;
        this.hiddenValue = hiddenValue;
    }
}


public class SerializedNameOnlyStrategy implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(SerializedName.class) == null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}


Gson gson = new GsonBuilder()
                .setExclusionStrategies(new SerializedNameOnlyStrategy())
                .create();

Dummy dummy = new Dummy("I will see this","I will not see this");
String json = gson.toJson(dummy);

Powraca

{„VisibleValue”: „Zobaczę to”}

MadMurdok
źródło
6

Innym podejściem (szczególnie przydatnym, jeśli trzeba podjąć decyzję o wykluczeniu pola w czasie wykonywania) jest zarejestrowanie TypeAdapter w instancji gson. Przykład poniżej:

Gson gson = new GsonBuilder()
.registerTypeAdapter(BloodPressurePost.class, new BloodPressurePostSerializer())

W poniższym przypadku serwer oczekiwałby jednej z dwóch wartości, ale ponieważ obie były ints, gson serializował je obie. Moim celem było pominięcie wartości zerowej (lub mniejszej) w pliku Json wysyłanym na serwer.

public class BloodPressurePostSerializer implements JsonSerializer<BloodPressurePost> {

    @Override
    public JsonElement serialize(BloodPressurePost src, Type typeOfSrc, JsonSerializationContext context) {
        final JsonObject jsonObject = new JsonObject();

        if (src.systolic > 0) {
            jsonObject.addProperty("systolic", src.systolic);
        }

        if (src.diastolic > 0) {
            jsonObject.addProperty("diastolic", src.diastolic);
        }

        jsonObject.addProperty("units", src.units);

        return jsonObject;
    }
}
Damian
źródło
6

@TransientAdnotacja Kotlina najwyraźniej rozwiązuje ten problem.

data class Json(
    @field:SerializedName("serialized_field_1") val field1: String,
    @field:SerializedName("serialized_field_2") val field2: String,
    @Transient val field3: String
)

Wynik:

{"serialized_field_1":"VALUE1","serialized_field_2":"VALUE2"}
lookashc
źródło
1

Pracuję, umieszczając @Exposeadnotację, tutaj moja wersja, której używam

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

W Modelklasie:

@Expose
int number;

public class AdapterRestApi {

W Adapterklasie:

public EndPointsApi connectRestApi() {
    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(90000, TimeUnit.SECONDS)
            .readTimeout(90000,TimeUnit.SECONDS).build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ConstantRestApi.ROOT_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();

    return retrofit.create  (EndPointsApi.class);
}
devitoper
źródło
1

Mam wersję Kotlin

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
internal annotation class JsonSkip

class SkipFieldsStrategy : ExclusionStrategy {

    override fun shouldSkipClass(clazz: Class<*>): Boolean {
        return false
    }

    override fun shouldSkipField(f: FieldAttributes): Boolean {
        return f.getAnnotation(JsonSkip::class.java) != null
    }
}

i jak możesz to dodać do Retrofit GSONConverterFactory:

val gson = GsonBuilder()
                .setExclusionStrategies(SkipFieldsStrategy())
                //.serializeNulls()
                //.setDateFormat(DateFormat.LONG)
                //.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
                //.setPrettyPrinting()
                //.registerTypeAdapter(Id.class, IdTypeAdapter())
                .create()
        return GsonConverterFactory.create(gson)
Michał Ziobro
źródło
0

Tego zawsze używam:

Domyślnym zachowaniem zaimplementowanym w Gson jest ignorowanie pól obiektów zerowych.

Oznacza, że ​​obiekt Gson nie serializuje pól z zerowymi wartościami do JSON. Jeśli pole w obiekcie Java ma wartość NULL, Gson je wyklucza.

Możesz użyć tej funkcji, aby przekonwertować jakiś obiekt na null lub dobrze ustawiony samodzielnie

     /**
   * convert object to json
   */
  public String toJson(Object obj) {
    // Convert emtpy string and objects to null so we don't serialze them
    setEmtpyStringsAndObjectsToNull(obj);
    return gson.toJson(obj);
  }

  /**
   * Sets all empty strings and objects (all fields null) including sets to null.
   *
   * @param obj any object
   */
  public void setEmtpyStringsAndObjectsToNull(Object obj) {
    for (Field field : obj.getClass().getDeclaredFields()) {
      field.setAccessible(true);
      try {
        Object fieldObj = field.get(obj);
        if (fieldObj != null) {
          Class fieldType = field.getType();
          if (fieldType.isAssignableFrom(String.class)) {
            if(fieldObj.equals("")) {
              field.set(obj, null);
            }
          } else if (fieldType.isAssignableFrom(Set.class)) {
            for (Object item : (Set) fieldObj) {
              setEmtpyStringsAndObjectsToNull(item);
            }
            boolean setFielToNull = true;
            for (Object item : (Set) field.get(obj)) {
              if(item != null) {
                setFielToNull = false;
                break;
              }
            }
            if(setFielToNull) {
              setFieldToNull(obj, field);
            }
          } else if (!isPrimitiveOrWrapper(fieldType)) {
            setEmtpyStringsAndObjectsToNull(fieldObj);
            boolean setFielToNull = true;
            for (Field f : fieldObj.getClass().getDeclaredFields()) {
              f.setAccessible(true);
              if(f.get(fieldObj) != null) {
                setFielToNull = false;
                break;
              }
            }
            if(setFielToNull) {
              setFieldToNull(obj, field);
            }
          }
        }
      } catch (IllegalAccessException e) {
        System.err.println("Error while setting empty string or object to null: " + e.getMessage());
      }
    }
  }

  private void setFieldToNull(Object obj, Field field) throws IllegalAccessException {
    if(!Modifier.isFinal(field.getModifiers())) {
      field.set(obj, null);
    }
  }

  private boolean isPrimitiveOrWrapper(Class fieldType)  {
    return fieldType.isPrimitive()
        || fieldType.isAssignableFrom(Integer.class)
        || fieldType.isAssignableFrom(Boolean.class)
        || fieldType.isAssignableFrom(Byte.class)
        || fieldType.isAssignableFrom(Character.class)
        || fieldType.isAssignableFrom(Float.class)
        || fieldType.isAssignableFrom(Long.class)
        || fieldType.isAssignableFrom(Double.class)
        || fieldType.isAssignableFrom(Short.class);
  }
Julian Solarte
źródło