mirror of
https://github.com/fankes/moshi.git
synced 2025-10-20 00:19:21 +08:00
Fold the kotlin-codegen-runtime into Moshi itself.
Rename @MoshiSerializable to @JsonClass. Like @Json, I'm anticipating a future where there are other interesting properties on this annotation. Perhaps a future feature where Moshi is strict and only adapts types that have a '@JsonClass' annotation. Also rename MoshiKotlinCodeGenProcessor to JsonClassCodeGenProcessor. We may later support other ways of generating code here; perhaps for regular Java types.
This commit is contained in:
32
moshi/src/main/java/com/squareup/moshi/JsonClass.java
Normal file
32
moshi/src/main/java/com/squareup/moshi/JsonClass.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Square, Inc.
|
||||
*
|
||||
* 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.squareup.moshi;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Customizes how a type is encoded as JSON.
|
||||
*
|
||||
* <p>This annotation is currently only permitted on declarations of data classes in Kotlin.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
public @interface JsonClass {
|
||||
boolean generateAdapter();
|
||||
}
|
@@ -18,6 +18,9 @@ package com.squareup.moshi;
|
||||
import com.squareup.moshi.internal.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -53,6 +56,12 @@ final class StandardJsonAdapters {
|
||||
if (type == Object.class) return new ObjectJsonAdapter(moshi).nullSafe();
|
||||
|
||||
Class<?> rawType = Types.getRawType(type);
|
||||
|
||||
JsonClass jsonClass = rawType.getAnnotation(JsonClass.class);
|
||||
if (jsonClass != null && jsonClass.generateAdapter()) {
|
||||
return generatedAdapter(moshi, type, rawType);
|
||||
}
|
||||
|
||||
if (rawType.isEnum()) {
|
||||
//noinspection unchecked
|
||||
return new EnumJsonAdapter<>((Class<? extends Enum>) rawType).nullSafe();
|
||||
@@ -215,6 +224,45 @@ final class StandardJsonAdapters {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the generated JsonAdapter for classes annotated {@link JsonClass}. This works because it
|
||||
* uses the same naming conventions as {@code JsonClassCodeGenProcessor}.
|
||||
*/
|
||||
static JsonAdapter<?> generatedAdapter(Moshi moshi, Type type, Class<?> rawType) {
|
||||
String adapterClassName = rawType.getName().replace("$", "_") + "JsonAdapter";
|
||||
try {
|
||||
@SuppressWarnings("unchecked") // We generate types to match.
|
||||
Class<? extends JsonAdapter<?>> adapterClass = (Class<? extends JsonAdapter<?>>)
|
||||
Class.forName(adapterClassName, true, rawType.getClassLoader());
|
||||
if (type instanceof ParameterizedType) {
|
||||
Constructor<? extends JsonAdapter<?>> constructor
|
||||
= adapterClass.getDeclaredConstructor(Moshi.class, Type[].class);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(moshi, ((ParameterizedType) type).getActualTypeArguments());
|
||||
} else {
|
||||
Constructor<? extends JsonAdapter<?>> constructor
|
||||
= adapterClass.getDeclaredConstructor(Moshi.class);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(moshi);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to find the generated JsonAdapter class for " + rawType, e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to find the generated JsonAdapter constructor for " + rawType, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to access the generated JsonAdapter for " + rawType, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to construct the generated JsonAdapter for " + rawType, e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to instantiate the generated JsonAdapter for " + rawType, e);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
|
||||
private final Class<T> enumType;
|
||||
private final String[] nameStrings;
|
||||
|
Reference in New Issue
Block a user