Java tutorial
/* * Copyright (C) 2016 Andrey Mogilev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gilecode.yagson; import com.gilecode.yagson.refs.References; import com.gilecode.yagson.refs.ReferencesPolicy; import com.gilecode.yagson.types.TypeInfoPolicy; import com.gilecode.yagson.types.TypeUtils; import com.google.gson.*; import com.google.gson.internal.Excluder; import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.stream.JsonWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Type; import java.util.Collections; import java.util.List; import java.util.Map; /** * The main class for using YaGson. Along with {@link YaGsonBuilder}, it provides similar * creation and usage patterns as the basic {@link Gson}, but the references emitting and * the type info emitting are enabled by default. See {@link References#defaultPolicy()} and * {@link TypeInfoPolicy#defaultPolicy()} for the default YaGson's settings. * <p/> * If any non-default features are required, use {@link YaGsonBuilder} to create {@link YaGson} * instance. * * @author Andrey Mogilev */ public class YaGson extends Gson { /** * Constructs a Gson object with the default configuration. The default configuration has the * following settings: * <ul> * <li>By default, YaGson's detects all self-references and the duplicate objects in the whole references graph * of the serialized object. All such objects except the first one are emitted as link-like references, see * {@link ReferencesPolicy#DUPLICATE_OBJECTS}. Although this policy may be changed to the alternative ones by * {@link YaGsonBuilder#setReferencesPolicy(ReferencesPolicy)}, it is not recommended in case of arbitrary objects, * as the functionality of the deserialized objects may be broken.</li> * <li>By default, the type information is emitted as {@literal @type/@value} wrappers when the actual types * would be lost otherwise, i.e. when the known de-serialization type is less specific than the actual class * of an object or its part being serialized. Use * {@link YaGsonBuilder#setTypeInfoPolicy(TypeInfoPolicy)} to change it if necessary.</li> * <li>The JSON generated by <code>toJson</code> methods is in compact representation. This * means that all the unneeded white-space is removed. You can change this behavior with * {@link GsonBuilder#setPrettyPrinting()}. </li> * <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are * kept as is since an array is an ordered list. Moreover, if a field is not null, but its * generated JSON is empty, the field is kept. You can configure Gson to serialize null values * by setting {@link GsonBuilder#serializeNulls()}.</li> * <li>The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format * ignores the millisecond portion of the date during serialization. You can change * this by invoking {@link GsonBuilder#setDateFormat(int)} or * {@link GsonBuilder#setDateFormat(String)}. </li> * <li>By default, Gson ignores the {@link com.google.gson.annotations.Expose} annotation. * You can enable Gson to serialize/deserialize only those fields marked with this annotation * through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. </li> * <li>By default, Gson ignores the {@link com.google.gson.annotations.Since} annotation. You * can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.</li> * <li>The default field naming policy for the output Json is same as in Java. So, a Java class * field <code>versionNumber</code> will be output as <code>"versionNumber"</code> in * Json. The same rules are applied for mapping incoming Json to the Java classes. You can * change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</li> * <li>By default, YaGson excludes <code>static</code> fields from * consideration for serialization and deserialization, but serializes most of <code>transient</code> * fields. * You can change this behavior through * {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li> * </ul> */ public YaGson() { super(Excluder.DEFAULT.forReferencesPolicy(References.defaultPolicy()), FieldNamingPolicy.IDENTITY, Collections.<Type, InstanceCreator<?>>emptyMap(), false, TypeInfoPolicy.defaultPolicy().isEnabled(), DEFAULT_JSON_NON_EXECUTABLE, !TypeInfoPolicy.defaultPolicy().isEnabled(), // disable htmlSafe if types are printed false, false, LongSerializationPolicy.DEFAULT, Collections.<TypeAdapterFactory>emptyList(), References.defaultPolicy(), TypeInfoPolicy.defaultPolicy()); } protected YaGson(Excluder excluder, FieldNamingStrategy fieldNamingPolicy, Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy, List<TypeAdapterFactory> typeAdapterFactories, ReferencesPolicy referencesPolicy, TypeInfoPolicy typeInfoPolicy) { super(excluder, fieldNamingPolicy, instanceCreators, serializeNulls, complexMapKeySerialization, generateNonExecutableGson, htmlSafe, prettyPrinting, serializeSpecialFloatingPointValues, longSerializationPolicy, typeAdapterFactories, referencesPolicy, typeInfoPolicy); } /** * This method serializes the specified object into its equivalent Json representation, provided that * the de-serialization type is not known at this time. * <p/> * By default, the root type information is emitted, unless the object is a string, long, double or boolean, so * the resulting JSON string may be successfully de-serialized into the similar object using * {@code fromJson(str, Object.class)}. If the object will be de-serialized using some other type than * {@code Object.class}, use {@link #toJson(Object, Type)} instead, and the root type information will be * emitted only when necessary, i.e. if the de-serialization type differs from the actual one. * <p/> * If you want to write out the object to a {@link Writer}, use {@link #toJson(Object, Appendable)} instead. * * @param src the object for which Json representation is to be created * @return Json representation of {@code src}. */ @Override public String toJson(Object src) { return toJson(src, Object.class); } /** * This method serializes the specified object into its equivalent Json representation, given that the * de-serialization type is known. * <p/> * The root type information is emitted only if necessary, i.e. if the specified de-serialization type differs from * the actual object's class. It is guaranteed that the resulting string may be de-serialized to the similar object * using {@code fromJson(json, deserializationType)}, unless some YaGson's features are disabled. * <p/> * If you want to write out the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} * instead. * * @param src the object for which JSON representation is to be created * @param deserializationType The type which will be used for de-serialization of the resulting JSON representation * @return Json representation of {@code src} */ @Override public String toJson(Object src, Type deserializationType) { StringWriter writer = new StringWriter(); toJson(src, deserializationType, writer); return writer.toString(); } /** * This method serializes the specified object into its equivalent Json representation, provided that * the de-serialization type is not known at this time. * <p/> * By default, the root type information is emitted, unless the object is a string, long, double or boolean, so * the resulting JSON string may be successfully de-serialized into the similar object using * {@code fromJson(str, Object.class)}. If the object will be de-serialized using some other type than * {@code Object.class}, use {@link #toJson(Object, Type, Appendable)} instead, and the root type information * will be emitted only when necessary, i.e. if the de-serialization type differs from the actual one. * * @param src the object for which Json representation is to be created * @param writer Writer to which the Json representation needs to be written * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 */ @Override public void toJson(Object src, Appendable writer) throws JsonIOException { toJson(src, Object.class, writer); } /** * This method serializes the specified object into its equivalent Json representation, given that the * de-serialization type is known, and writes it to the provided {@link Appendable}. * <p/> * The root type information is emitted only if necessary, i.e. if the specified de-serialization type differs from * the actual object's class. It is guaranteed that the resulting JSON representation may be de-serialized to the * similar object using {@code fromJson(json, deserializationType)}, unless some YaGson's features are disabled. * * @param src the object for which JSON representation is to be created * @param deserializationType The type which will be used for de-serialization of the resulting JSON representation * @param writer Writer to which the Json representation of src needs to be written. * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 */ @Override public void toJson(Object src, Type deserializationType, Appendable writer) throws JsonIOException { // forwards to {@link #toJson(Object, Type, JsonWriter)} super.toJson(src, deserializationType, writer); } /** * This method serializes the specified object into its equivalent Json representation, given that the * de-serialization type is known, and writes it to the provided {@link JsonWriter}. * <p/> * The root type information is emitted only if necessary, i.e. if the specified de-serialization type differs from * the actual object's class. It is guaranteed that the resulting JSON representation may be de-serialized to the * similar object using {@code fromJson(json, deserializationType)}, unless some YaGson's features are disabled. * * @param src the object for which JSON representation is to be created * @param deserializationType The type which will be used for de-serialization of the resulting JSON representation * @param writer Writer to which the Json representation of src needs to be written. * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 */ @Override public void toJson(Object src, Type deserializationType, JsonWriter writer) throws JsonIOException { if (src == null) { toJson(JsonNull.INSTANCE, writer); return; } if (src instanceof Number && TypeUtils.isNumberType(deserializationType) && TypeUtils.typesDiffer(deserializationType, src.getClass())) { // a special case, where a user may rely on auto-cast of primitive number types // perform such cast here src = TypeUtils.convertNumber((Number) src, deserializationType); } boolean isRootTypeRequired = TypeUtils.isTypeInfoRequired(src.getClass(), deserializationType, false); // use the exact source class for serialization, but try to keep the type parameters if available in // the specified deserialization type Type parameterizedSrcType = TypeUtils.mergeTypes(src.getClass(), deserializationType); super.toJson(src, parameterizedSrcType, writer, isRootTypeRequired); } /** * This method serializes the specified object into its equivalent Json representation as a tree of * {@link JsonElement}s, provided that the de-serialization type is not known at this time. * <p/> * By default, the root type information is emitted, unless the object is a string, long, double or boolean, so * the resulting JSON string may be successfully de-serialized into the similar object using * {@code fromJson(str, Object.class)}. If the object will be de-serialized using some other type than * {@code Object.class}, use {@link #toJsonTree(Object, Type)} instead, and the root type information will be * emitted only when necessary, i.e. if the de-serialization type differs from the actual one. * * @param src the object for which Json representation is to be created * @return Json representation of {@code src}. */ @Override public JsonElement toJsonTree(Object src) { return toJsonTree(src, Object.class); } /** * This method serializes the specified object into its equivalent Json representation as a tree of * {@link JsonElement}s, given that the de-serialization type is known. * <p/> * The root type information is emitted only if necessary, i.e. if the specified de-serialization type differs from * the actual object's class. It is guaranteed that the resulting string may be de-serialized to the similar object * using {@code fromJson(json, deserializationType)}, unless some YaGson's features are disabled. * * @param src the object for which JSON representation is to be created * @param deserializationType The type which will be used for de-serialization of the resulting JSON representation * @return Json representation of {@code src} */ @Override public JsonElement toJsonTree(Object src, Type deserializationType) { if (src == null) { return JsonNull.INSTANCE; } boolean isRootTypeRequired = TypeUtils.isTypeInfoRequired(src.getClass(), deserializationType, false); JsonTreeWriter writer = new JsonTreeWriter(); super.toJson(src, src.getClass(), writer, isRootTypeRequired); return writer.get(); } }