-
-
Save JakeWharton/0d67d01badcee0ae7bc9 to your computer and use it in GitHub Desktop.
import com.google.auto.value.AutoValue; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.Target; | |
import static java.lang.annotation.ElementType.TYPE; | |
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |
/** | |
* Marks an {@link AutoValue @AutoValue}-annotated type for proper Gson serialization. | |
* <p> | |
* This annotation is needed because the {@linkplain Retention retention} of {@code @AutoValue} | |
* does not allow reflection at runtime. | |
*/ | |
@Target(TYPE) | |
@Retention(RUNTIME) | |
public @interface AutoGson { | |
} |
import com.google.gson.Gson; | |
import com.google.gson.TypeAdapter; | |
import com.google.gson.TypeAdapterFactory; | |
import com.google.gson.reflect.TypeToken; | |
public final class AutoValueAdapterFactory implements TypeAdapterFactory { | |
@SuppressWarnings("unchecked") | |
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | |
Class<? super T> rawType = type.getRawType(); | |
if (!rawType.isAnnotationPresent(AutoGson.class)) { | |
return null; | |
} | |
String packageName = rawType.getPackage().getName(); | |
String className = rawType.getName().substring(packageName.length() + 1).replace('$', '_'); | |
String autoValueName = packageName + ".AutoValue_" + className; | |
try { | |
Class<?> autoValueType = Class.forName(autoValueName); | |
return (TypeAdapter<T>) gson.getAdapter(autoValueType); | |
} catch (ClassNotFoundException e) { | |
throw new RuntimeException("Could not load AutoValue type " + autoValueName, e); | |
} | |
} | |
} |
import com.google.auto.value.AutoValue; | |
import com.google.gson.Gson; | |
import com.google.gson.GsonBuilder; | |
public class Main { | |
public static void main(String... args) { | |
Gson gson = new GsonBuilder() | |
.registerTypeAdapterFactory(new AutoValueAdapterFactory()) | |
.create(); | |
Test inTest = Test.of("John", "Doe", 100); | |
System.out.println("IN: " + inTest); | |
String json = gson.toJson(inTest); | |
System.out.println("JSON: " + json); | |
Test outTest = gson.fromJson(json, Test.class); | |
System.out.println("OUT: " + outTest); | |
} | |
@AutoValue @AutoGson | |
public abstract static class Test { | |
public static Test of(String firstName, String lastName, int age) { | |
return new AutoValue_Main_Test(firstName, lastName, age); | |
} | |
public abstract String firstName(); | |
public abstract String lastName(); | |
public abstract int age(); | |
} | |
} | |
Hi!
I'm trying to test this chunk of code and I'm always bumping into a no-args contructor problem.
Looking at the code generated by AutoValue, there is indeed no no-args constructor (as it should, afaik).
What am I missing?
Thanks!
@codedance That is far too presumptuous to work at scale.
Is there a way how to use @SerializedName with AutoValue and this TypeAdapterFactory?
@semanticer https://github.com/rharter/auto-value-gson supports @SerializedName
.
Also interested in adding SerializedName.
Ok, what about Builders ? AutoValue for android support builder pattern, however when i use it with your @AutoGson it's giving me objects full of nulls. Is there any good way to go or i need to write my own solution ?
Does this work with generics?
@AutoValue @AutoGson
public abstract static class Some<T> {
public static Some <X> of(String firstName, String lastName, int age, X genericData) {
return new AutoValue_Main_Test<>(firstName, lastName, age, genericData);
}
public abstract String firstName();
public abstract String lastName();
public abstract int age();
public abstract T genericData();
}
When you do something like:
public class People {
List<Some<Map<String,String>> someList;
}
And try to parse a "People" json, will the generic be resolved?
@danielesegato https://github.com/rharter/auto-value-gson works with generics
Rather than using a new Annotation, testing for an abstract class may be a little more automatic.