Gson: comment exclure des champs spécifiques de la sérialisation sans annotations

413

J'essaie d'apprendre Gson et je lutte contre l'exclusion de terrain. Voici mes cours

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;
}

Je peux utiliser le GsonBuilder et ajouter une ExclusionStrategy pour un nom de champ comme firstNameou countrymais je n'arrive pas à exclure les propriétés de certains champs comme country.name.

En utilisant la méthode public boolean shouldSkipField(FieldAttributes fa), FieldAttributes ne contient pas suffisamment d'informations pour faire correspondre le champ avec un filtre comme country.name.

PS: Je veux éviter les annotations car je veux améliorer cela et utiliser RegEx pour filtrer les champs.

Edit : j'essaie de voir s'il est possible d'émuler le comportement du plugin Struts2 JSON

en utilisant Gson

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

Edit: J'ai rouvert la question avec l'ajout suivant:

J'ai ajouté un deuxième champ avec le même type pour clarifier ce problème. Fondamentalement, je veux exclure country.namemais pas countrOfBirth.name. Je ne veux pas non plus exclure Country en tant que type. Donc, les types sont les mêmes, c'est la place réelle dans le graphique d'objet que je veux localiser et exclure.

Liviu T.
la source
1
Toujours à partir de la version 2.2, je ne peux toujours pas spécifier de chemin d'accès au champ à exclure. flexjson.sourceforge.net se sent comme une bonne alternative.
Liviu T.
Jetez un œil à ma réponse à une question assez similaire. Il est basé sur la création d'une coutume JsonSerializerpour un certain type - Countrydans votre cas - pour laquelle est ensuite appliqué un ExclusionStrategyqui décide quels champs à sérialiser.
pirho

Réponses:

625

Tous les champs que vous ne voulez pas sérialiser en général, vous devez utiliser le modificateur "transitoire", et cela s'applique également aux sérialiseurs json (au moins c'est le cas pour quelques-uns que j'ai utilisés, y compris gson).

Si vous ne voulez pas que le nom apparaisse dans le json sérialisé, donnez-lui un mot-clé transitoire, par exemple:

private transient String name;

Plus de détails dans la documentation Gson

Chris Seline
la source
6
c'est presque la même chose qu'une annotation d'exclusion car elle s'applique à toutes les instances de cette classe. Je voulais une exclusion dynamique à l'exécution. Dans certains cas, je souhaite que certains champs soient exclus afin de fournir une réponse plus claire / restreinte et dans d'autres, je veux que l'intégralité de l'objet soit sérialisée
Liviu T.
34
Une chose à noter est que les effets transitoires affectent à la fois la sérialisation et la désérialisation. Il émettra également la valeur de a été sérialisé dans l'objet, même s'il est présent dans le JSON.
Kong
3
Le problème avec l'utilisation transientau lieu de @Exposeest que vous devez toujours simuler un POJO sur votre client avec tous les champs qui pourraient éventuellement entrer. Dans le cas d'une API principale qui pourrait être partagée entre les projets, cela pourrait être problématique au cas où des champs supplémentaires sont ajoutés. Il s'agit essentiellement d'une liste blanche par rapport à une liste noire des champs.
theblang
11
Cette approche n'a pas fonctionné pour moi, car elle a non seulement exclu le champ de la sérialisation gson, mais a exclu le champ de la sérialisation de l'application interne (à l'aide de l'interface sérialisable).
pkk
8
transitoire empêche la SERIALISATION et la DESERIALISATION d'un champ. Cela ne correspond pas à mes besoins.
Loenix
318

Nishant a fourni une bonne solution, mais il existe un moyen plus simple. Marquez simplement les champs souhaités avec l'annotation @Expose, tels que:

@Expose private Long id;

Omettez tous les champs que vous ne souhaitez pas sérialiser. Ensuite, créez simplement votre objet Gson de cette façon:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
JayPea
la source
95
Est-il possible d'avoir quelque chose comme "notExpose" et de ne les ignorer que dans le cas où tous les champs sauf un doivent être sérialisés et ajouter des annotations à tous est redondant?
Daniil Shevelev
2
@DaSh J'ai récemment eu un tel scénario. Il était très facile d'écrire une stratégie d'exclusion personnalisée qui faisait exactement cela. Voir la réponse de Nishant. Le seul problème était d'inclure un tas de classes de conteneurs et de jouer avec skipclass vs skipfield (les champs peuvent être des classes ...)
keyser
1
@DaSh Ma réponse ci-dessous fait exactement cela.
Derek Shockey
Quelle excellente solution. Je courais dans un scénario où je veux un champ sérialisé sur disque mais à ignorer lors de son envoi à un serveur via gson. Parfait merci!
Slynk
1
@Danlil Vous devriez pouvoir utiliser @Expose (serialize = false, deserialize = false)
Hrk
238

Donc, vous voulez exclure firstName et country.name. Voici à quoi ExclusionStrategydevrait ressembler votre

    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"));
        }

    }

Si vous voyez de près, il revient truepour Student.firstNameet Country.name, ce que vous voulez exclure.

Vous devez appliquer ceci ExclusionStrategycomme ceci,

    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);

Cela renvoie:

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

Je suppose que l'objet country est initialisé avec id = 91Len classe d'étudiant.


Vous pouvez devenir fantaisiste. Par exemple, vous ne voulez sérialiser aucun champ contenant une chaîne "nom" dans son nom. Faites ceci:

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

Cela reviendra:

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

EDIT: Ajout d'informations supplémentaires comme demandé.

Cela ExclusionStrategyfera l'affaire, mais vous devez passer "Nom de champ entièrement qualifié". Voir ci-dessous:

    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));
        }

    }

Voici comment nous pouvons l'utiliser de manière générique.

    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); 

Il renvoie:

{ "firstName": "Philip" , "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91 }}
Nishant
la source
Merci pour votre réponse. Ce que je veux, c'est créer une ExclusionStrategy qui peut prendre une chaîne comme country.nameet exclure le champ uniquement namelors de la sérialisation du champ country. Il doit être suffisamment générique pour s'appliquer à chaque classe possédant une propriété nommée country de la classe Country. Je ne veux pas créer une stratégie d'exclusion pour chaque classe
Liviu T.
@Liviu T. J'ai mis à jour la réponse. Cela prend une approche générique. Vous pouvez devenir encore plus créatif, mais je l'ai gardé élémentaire.
Nishant
Ty pour la mise à jour. Ce que j'essaie de voir s'il est possible de savoir où dans le graphique d'objet je suis lorsque la méthode qu'il a appelée afin que je puisse exclure certains champs de country mais pas countryOfBirth (par exemple) donc la même classe mais des propriétés différentes. J'ai édité ma question pour clarifier ce que j'essaie de réaliser
Liviu T.
Existe-t-il un moyen d'exclure des champs dont les valeurs sont vides?
Yusuf K.
12
Cette réponse doit être marquée comme la réponse préférée. Contrairement aux autres réponses qui ont actuellement plus de votes, cette solution ne vous oblige pas à modifier la classe du bean. C'est un énorme avantage. Que se passerait-il si quelqu'un d'autre utilisait la même classe de bean et que vous marquiez un champ qu'ils voulaient persisté comme "transitoire"?
user64141
221

Après avoir lu toutes les réponses disponibles, j'ai découvert que le plus flexible, dans mon cas, était d'utiliser des @Excludeannotations personnalisées . Donc, j'ai mis en place une stratégie simple pour cela (je ne voulais pas marquer tous les champs à l'aide @Exposeni je voulais utiliser transientqui était en conflit avec la Serializablesérialisation dans l'application ):

Annotation:

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

Stratégie:

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;
    }
}

Usage:

new GsonBuilder().setExclusionStrategies(new AnnotationExclusionStrategy()).create();
pkk
la source
16
Comme note supplémentaire, si vous souhaitez utiliser votre stratégie d'exclusion uniquement pour la sérialisation ou la désérialisation, utilisez: addSerializationExclusionStrategyou addDeserializationExclusionStrategyau lieu desetExclusionStrategies
GLee
9
Parfait! La solution transitoire ne fonctionne pas pour moi car j'utilise Realm pour DB et je veux exclure un champ uniquement de Gson, mais pas Realm (ce qui est transitoire)
Marcio Granzotto
3
Ce devrait être la réponse acceptée. Pour ignorer les champs null changent juste f.getAnnotation(Exclude.class) != nullàf.getAnnotation(Exclude.class) == null
bord de Sharp
3
Excellent lorsque vous ne pouvez pas l'utiliser en transientraison des besoins d'autres bibliothèques. Merci!
Martin D
1
Aussi génial pour moi car Android sérialise mes cours entre les activités, mais je ne veux les exclure que lorsque j'utilise GSON. Cela permet à mon application de continuer à fonctionner de la même manière jusqu'à ce qu'elle veuille les envelopper pour les envoyer à d'autres.
ThePartyTurtle
81

J'ai rencontré ce problème, dans lequel j'avais un petit nombre de champs que je voulais exclure uniquement de la sérialisation, j'ai donc développé une solution assez simple qui utilise l' @Exposeannotation de Gson avec des stratégies d'exclusion personnalisées.

La seule manière intégrée d'utiliser @Exposeest de définir GsonBuilder.excludeFieldsWithoutExposeAnnotation(), mais comme son nom l'indique, les champs sans explicite @Exposesont ignorés. Comme je n'avais que quelques champs que je voulais exclure, j'ai trouvé la perspective d'ajouter l'annotation à chaque champ très lourde.

En fait, je voulais l'inverse, dans lequel tout était inclus, sauf si je l'exclus explicitement @Expose. J'ai utilisé les stratégies d'exclusion suivantes pour y parvenir:

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();

Maintenant, je peux facilement exclure quelques champs avec @Expose(serialize = false)ou des @Expose(deserialize = false)annotations (notez que la valeur par défaut pour les deux @Exposeattributs est true). Vous pouvez bien sûr utiliser @Expose(serialize = false, deserialize = false), mais cela est accompli de manière plus concise en déclarant le champ à la transientplace (qui prend toujours effet avec ces stratégies d'exclusion personnalisées).

Derek Shockey
la source
Pour plus d'efficacité, je peux voir un cas d'utilisation de @Expose (serialize = false, deserialize = false) plutôt que transitoire.
paiego
1
@paiego Pouvez-vous développer cela? Je suis maintenant éloigné de nombreuses années de l'utilisation de Gson, et je ne comprends pas pourquoi l'annotation est plus efficace que de la marquer comme transitoire.
Derek Shockey
Ahh, j'ai fait une erreur, merci d'avoir attrapé ça. J'ai confondu volatile et transitoire. (Par exemple, il n'y a pas de mise en cache et donc pas de problème de cohérence de cache avec volatile, mais c'est moins performant) Quoi qu'il en soit, votre code a très bien fonctionné!
paiego
18

Vous pouvez explorer l'arbre json avec gson.

Essayez quelque chose comme ceci:

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

Vous pouvez également ajouter certaines propriétés:

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

Testé avec gson 2.2.4.

Klaudia Rzewnicka
la source
3
Je me demande si c'est trop de performances si vous voulez vous débarrasser d'une propriété complexe qui doit être analysée avant d'être supprimée. Pensées?
Ben
Certainement pas une solution évolutive, imaginez tout le mal de tête que vous aurez à traverser si vous changez la structure de votre objet ou ajoutez / supprimez des éléments.
codenamezero
16

J'ai créé une usine de classe pour prendre en charge cette fonctionnalité. Passez n'importe quelle combinaison de champs ou de classes que vous souhaitez exclure.

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();

    }
}

Pour l'utiliser, créez deux listes (chacune est facultative) et créez votre objet 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.
la source
Bien sûr, cela peut être modifié pour regarder le nom complet de l'attribut et exclure cela lors d'une correspondance ...
Domenic D.
Je fais l'exemple ci-dessous. Cela ne fonctionne pas. Les pls suggèrent une finale statique statique Gson GSON; static {List <String> fieldExclusions = new ArrayList <String> (); fieldExclusions.add ("id"); GSON = GsonFactory.build (fieldExclusions, null); } chaîne statique privée getSomeJson () {chaîne jsonStr = "[{\" id \ ": 111, \" nom \ ": \" praveen \ ", \" age \ ": 16}, {\" id \ ": 222, \ "nom \": \ "prashant \", \ "age \": 20}] "; return jsonStr; } public static void main (String [] args) {String jsonStr = getSomeJson (); System.out.println (GSON.toJson (jsonStr)); }
Praveen Hiremath
13

J'ai résolu ce problème avec des annotations personnalisées. Voici ma classe d'annotation "SkipSerialisation":

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

}

et voici mon 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;
  }
});

Exemple :

public class User implements Serializable {

  public String firstName;

  public String lastName;

  @SkipSerialisation
  public String email;
}
Hibbem
la source
5
Gson: Comment exclure des champs spécifiques de la sérialisation sans annotations
Ben
3
Vous devez également ajouter @Retention(RetentionPolicy.RUNTIME)à votre annotation.
David Novák
9

Ou peut dire quels champs ne seront pas exposés avec:

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

sur votre classe sur l'attribut:

private **transient** boolean nameAttribute;
lucasddaniel
la source
17
Les champs transitoires et statiques sont exclus par défaut; il n'est pas nécessaire d'appeler excludeFieldsWithModifiers()cela.
Derek Shockey
9

J'ai utilisé cette stratégie: j'ai exclu chaque champ qui n'est pas marqué avec l' annotation @SerializedName , c'est-à-dire:

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);

Il revient

{"VisibleValue": "Je verrai ceci"}

MadMurdok
la source
6

Une autre approche (particulièrement utile si vous devez prendre la décision d'exclure un champ au moment de l'exécution) consiste à enregistrer un TypeAdapter avec votre instance gson. Exemple ci-dessous:

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

Dans le cas ci-dessous, le serveur attendrait l'une des deux valeurs, mais comme il s'agissait de deux entiers, gson les sérialiserait tous les deux. Mon objectif était d'omettre toute valeur qui est zéro (ou moins) du json qui est publié sur le serveur.

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
la source
6

L' @Transientannotation de Kotlin fait aussi apparemment l'affaire.

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

Production:

{"serialized_field_1":"VALUE1","serialized_field_2":"VALUE2"}
lookashc
la source
1

Je travaille juste en mettant l' @Exposeannotation, voici ma version que j'utilise

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

En Modelclasse:

@Expose
int number;

public class AdapterRestApi {

En Adapterclasse:

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
la source
1

J'ai la version 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
    }
}

et comment vous pouvez l'ajouter à 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
la source
0

C'est ce que j'utilise toujours:

Le comportement par défaut implémenté dans Gson est que les champs d'objet null sont ignorés.

Signifie que l'objet Gson ne sérialise pas les champs avec des valeurs nulles en JSON. Si un champ dans un objet Java est nul, Gson l'exclut.

Vous pouvez utiliser cette fonction pour convertir un objet en null ou bien défini par vous-même

     /**
   * 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
la source