Move modules into their own packages.

This sets the Automatic-Module-Name for moshi, moshi-adapters, and moshi-kotlin.
It moves moshi-adapters into its own .adapters package and forwards the existing
adapter. It moves the moshi-kotlin into its own .kotlin package and forwards the
existing adapter.

I'm not certain this is necessary or sufficient, but I think it's the right idea
for JPMS compatibility.
This commit is contained in:
Jesse Wilson
2018-02-07 04:33:40 -05:00
parent d26b2a151f
commit 5ad9d31bd8
20 changed files with 391 additions and 261 deletions

View File

@@ -33,4 +33,20 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>com.squareup.moshi.adapters</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -19,17 +19,18 @@ import java.io.IOException;
import java.util.Date;
/**
* Formats dates using <a href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</a>, which is
* formatted like {@code 2015-09-26T18:23:50.250Z}.
* @deprecated this class moved to avoid a package name conflict in the Java Platform Module System.
* The new class is {@code com.squareup.moshi.adapters.Rfc3339DateJsonAdapter}.
*/
public final class Rfc3339DateJsonAdapter extends JsonAdapter<Date> {
@Override public synchronized Date fromJson(JsonReader reader) throws IOException {
String string = reader.nextString();
return Iso8601Utils.parse(string);
com.squareup.moshi.adapters.Rfc3339DateJsonAdapter delegate
= new com.squareup.moshi.adapters.Rfc3339DateJsonAdapter();
@Override public Date fromJson(JsonReader reader) throws IOException {
return delegate.fromJson(reader);
}
@Override public synchronized void toJson(JsonWriter writer, Date value) throws IOException {
String string = Iso8601Utils.format(value);
writer.value(string);
@Override public void toJson(JsonWriter writer, Date value) throws IOException {
delegate.toJson(writer, value);
}
}

View File

@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi;
package com.squareup.moshi.adapters;
import com.squareup.moshi.JsonDataException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2015 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.adapters;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;
import java.io.IOException;
import java.util.Date;
/**
* Formats dates using <a href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</a>, which is
* formatted like {@code 2015-09-26T18:23:50.250Z}.
*/
public final class Rfc3339DateJsonAdapter extends JsonAdapter<Date> {
@Override public synchronized Date fromJson(JsonReader reader) throws IOException {
String string = reader.nextString();
return Iso8601Utils.parse(string);
}
@Override public synchronized void toJson(JsonWriter writer, Date value) throws IOException {
String string = Iso8601Utils.format(value);
writer.value(string);
}
}

View File

@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi;
package com.squareup.moshi.adapters;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

View File

@@ -17,7 +17,7 @@ package com.squareup.moshi.recipes;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Rfc3339DateJsonAdapter;
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter;
import com.squareup.moshi.recipes.models.Tournament;
import java.util.Calendar;
import java.util.Date;

View File

@@ -84,6 +84,17 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>com.squareup.moshi.kotlin</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -15,223 +15,9 @@
*/
package com.squareup.moshi
import java.lang.reflect.Modifier
import java.lang.reflect.Type
import java.util.AbstractMap.SimpleEntry
import kotlin.collections.Map.Entry
import kotlin.reflect.KFunction
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaType
/** Classes annotated with this are eligible for this adapter. */
private val KOTLIN_METADATA = Class.forName("kotlin.Metadata") as Class<out Annotation>
/**
* Placeholder value used when a field is absent from the JSON. Note that this code
* distinguishes between absent values and present-but-null values.
*/
private object ABSENT_VALUE
/**
* This class encodes Kotlin classes using their properties. It decodes them by first invoking the
* constructor, and then by setting any additional properties that exist, if any.
*/
internal class KotlinJsonAdapter<T>(
val constructor: KFunction<T>,
val bindings: List<Binding<T, Any?>?>,
val options: JsonReader.Options) : JsonAdapter<T>() {
override fun fromJson(reader: JsonReader): T {
val constructorSize = constructor.parameters.size
// Read each value into its slot in the array.
val values = Array<Any?>(bindings.size) { ABSENT_VALUE }
reader.beginObject()
while (reader.hasNext()) {
val index = reader.selectName(options)
val binding = if (index != -1) bindings[index] else null
if (binding == null) {
reader.nextName()
reader.skipValue()
continue
}
if (values[index] !== ABSENT_VALUE) {
throw JsonDataException(
"Multiple values for ${constructor.parameters[index].name} at ${reader.path}")
}
values[index] = binding.adapter.fromJson(reader)
}
reader.endObject()
// Confirm all parameters are present, optional, or nullable.
for (i in 0 until constructorSize) {
if (values[i] === ABSENT_VALUE && !constructor.parameters[i].isOptional) {
if (!constructor.parameters[i].type.isMarkedNullable) {
throw JsonDataException(
"Required value ${constructor.parameters[i].name} missing at ${reader.path}")
}
values[i] = null // Replace absent with null.
} else if (values[i] == null && !constructor.parameters[i].type.isMarkedNullable) {
throw JsonDataException("Non-null value ${constructor.parameters[i].name} " +
"was null at ${reader.path}")
}
}
// Call the constructor using a Map so that absent optionals get defaults.
val result = constructor.callBy(IndexedParameterMap(constructor.parameters, values))
// Set remaining properties.
for (i in constructorSize until bindings.size) {
val binding = bindings[i]!!
val value = values[i]
if (value == null && !binding.property.returnType.isMarkedNullable) {
throw JsonDataException("Non-null value ${binding.property.name} " +
"was null at ${reader.path}")
}
binding.set(result, value)
}
return result
}
override fun toJson(writer: JsonWriter, value: T?) {
if (value == null) throw NullPointerException("value == null")
writer.beginObject()
for (binding in bindings) {
if (binding == null) continue // Skip constructor parameters that aren't properties.
writer.name(binding.name)
binding.adapter.toJson(writer, binding.get(value))
}
writer.endObject()
}
override fun toString() = "KotlinJsonAdapter(${constructor.returnType})"
data class Binding<K, P>(
val name: String,
val adapter: JsonAdapter<P>,
val property: KProperty1<K, P>,
val parameter: KParameter?) {
fun get(value: K) = property.get(value)
fun set(result: K, value: P) {
if (value !== ABSENT_VALUE) {
(property as KMutableProperty1<K, P>).set(result, value)
}
}
}
/** A simple [Map] that uses parameter indexes instead of sorting or hashing. */
class IndexedParameterMap(val parameterKeys: List<KParameter>, val parameterValues: Array<Any?>)
: AbstractMap<KParameter, Any?>() {
override val entries: Set<Entry<KParameter, Any?>>
get() {
val allPossibleEntries = parameterKeys.mapIndexed { index, value ->
SimpleEntry<KParameter, Any?>(value, parameterValues[index])
}
return allPossibleEntries.filterTo(LinkedHashSet<Entry<KParameter, Any?>>()) {
it.value !== ABSENT_VALUE
}
}
override fun containsKey(key: KParameter) = parameterValues[key.index] !== ABSENT_VALUE
override fun get(key: KParameter): Any? {
val value = parameterValues[key.index]
return if (value !== ABSENT_VALUE) value else null
}
}
}
class KotlinJsonAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi)
: JsonAdapter<*>? {
if (!annotations.isEmpty()) return null
val rawType = Types.getRawType(type)
if (rawType.isInterface) return null
if (rawType.isEnum) return null
if (!rawType.isAnnotationPresent(KOTLIN_METADATA)) return null
if (ClassJsonAdapter.isPlatformType(rawType)) return null
if (rawType.isLocalClass) {
throw IllegalArgumentException("Cannot serialize local class or object expression ${rawType.name}")
}
val rawTypeKotlin = rawType.kotlin
if (rawTypeKotlin.isAbstract) {
throw IllegalArgumentException("Cannot serialize abstract class ${rawType.name}")
}
if (rawTypeKotlin.isInner) {
throw IllegalArgumentException("Cannot serialize inner class ${rawType.name}")
}
if (rawTypeKotlin.objectInstance != null) {
throw IllegalArgumentException("Cannot serialize object declaration ${rawType.name}")
}
val constructor = rawTypeKotlin.primaryConstructor ?: return null
val parametersByName = constructor.parameters.associateBy { it.name }
constructor.isAccessible = true
val bindingsByName = LinkedHashMap<String, KotlinJsonAdapter.Binding<Any, Any?>>()
for (property in rawTypeKotlin.memberProperties) {
val parameter = parametersByName[property.name]
if (Modifier.isTransient(property.javaField?.modifiers ?: 0)) {
if (parameter != null && !parameter.isOptional) {
throw IllegalArgumentException(
"No default value for transient constructor $parameter")
}
continue
}
if (property !is KMutableProperty1 && parameter == null) continue
property.isAccessible = true
var allAnnotations = property.annotations
var jsonAnnotation = property.findAnnotation<Json>()
if (parameter != null) {
allAnnotations += parameter.annotations
if (jsonAnnotation == null) {
jsonAnnotation = parameter.findAnnotation<Json>()
}
}
val name = jsonAnnotation?.name ?: property.name
val adapter = moshi.adapter<Any>(
property.returnType.javaType, Util.jsonAnnotations(allAnnotations.toTypedArray()))
bindingsByName[property.name] =
KotlinJsonAdapter.Binding(name, adapter, property as KProperty1<Any, Any?>, parameter)
}
val bindings = ArrayList<KotlinJsonAdapter.Binding<Any, Any?>?>()
for (parameter in constructor.parameters) {
val binding = bindingsByName.remove(parameter.name)
if (binding == null && !parameter.isOptional) {
throw IllegalArgumentException("No property for required constructor ${parameter}")
}
bindings += binding
}
bindings += bindingsByName.values
val options = JsonReader.Options.of(*bindings.map { it?.name ?: "\u0000" }.toTypedArray())
return KotlinJsonAdapter(constructor, bindings, options).nullSafe()
}
}
@Deprecated(
message = "this moved to avoid a package name conflict in the Java Platform Module System.",
replaceWith = ReplaceWith("com.squareup.moshi.kotlin.KotlinJsonAdapterFactory")
)
class KotlinJsonAdapterFactory
: JsonAdapter.Factory by com.squareup.moshi.kotlin.KotlinJsonAdapterFactory()

View File

@@ -0,0 +1,245 @@
/*
* Copyright (C) 2017 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.kotlin
import com.squareup.moshi.Json
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.squareup.moshi.internal.Util
import java.lang.reflect.Modifier
import java.lang.reflect.Type
import java.util.AbstractMap.SimpleEntry
import kotlin.collections.Map.Entry
import kotlin.reflect.KFunction
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaType
/** Classes annotated with this are eligible for this adapter. */
private val KOTLIN_METADATA = Class.forName("kotlin.Metadata") as Class<out Annotation>
/**
* Placeholder value used when a field is absent from the JSON. Note that this code
* distinguishes between absent values and present-but-null values.
*/
private object ABSENT_VALUE
/**
* This class encodes Kotlin classes using their properties. It decodes them by first invoking the
* constructor, and then by setting any additional properties that exist, if any.
*/
internal class KotlinJsonAdapter<T>(
val constructor: KFunction<T>,
val bindings: List<Binding<T, Any?>?>,
val options: JsonReader.Options) : JsonAdapter<T>() {
override fun fromJson(reader: JsonReader): T {
val constructorSize = constructor.parameters.size
// Read each value into its slot in the array.
val values = Array<Any?>(bindings.size) { ABSENT_VALUE }
reader.beginObject()
while (reader.hasNext()) {
val index = reader.selectName(options)
val binding = if (index != -1) bindings[index] else null
if (binding == null) {
reader.nextName()
reader.skipValue()
continue
}
if (values[index] !== ABSENT_VALUE) {
throw JsonDataException(
"Multiple values for ${constructor.parameters[index].name} at ${reader.path}")
}
values[index] = binding.adapter.fromJson(reader)
}
reader.endObject()
// Confirm all parameters are present, optional, or nullable.
for (i in 0 until constructorSize) {
if (values[i] === ABSENT_VALUE && !constructor.parameters[i].isOptional) {
if (!constructor.parameters[i].type.isMarkedNullable) {
throw JsonDataException(
"Required value ${constructor.parameters[i].name} missing at ${reader.path}")
}
values[i] = null // Replace absent with null.
} else if (values[i] == null && !constructor.parameters[i].type.isMarkedNullable) {
throw JsonDataException("Non-null value ${constructor.parameters[i].name} " +
"was null at ${reader.path}")
}
}
// Call the constructor using a Map so that absent optionals get defaults.
val result = constructor.callBy(IndexedParameterMap(constructor.parameters, values))
// Set remaining properties.
for (i in constructorSize until bindings.size) {
val binding = bindings[i]!!
val value = values[i]
if (value == null && !binding.property.returnType.isMarkedNullable) {
throw JsonDataException("Non-null value ${binding.property.name} " +
"was null at ${reader.path}")
}
binding.set(result, value)
}
return result
}
override fun toJson(writer: JsonWriter, value: T?) {
if (value == null) throw NullPointerException("value == null")
writer.beginObject()
for (binding in bindings) {
if (binding == null) continue // Skip constructor parameters that aren't properties.
writer.name(binding.name)
binding.adapter.toJson(writer, binding.get(value))
}
writer.endObject()
}
override fun toString() = "KotlinJsonAdapter(${constructor.returnType})"
data class Binding<K, P>(
val name: String,
val adapter: JsonAdapter<P>,
val property: KProperty1<K, P>,
val parameter: KParameter?) {
fun get(value: K) = property.get(value)
fun set(result: K, value: P) {
if (value !== ABSENT_VALUE) {
(property as KMutableProperty1<K, P>).set(result, value)
}
}
}
/** A simple [Map] that uses parameter indexes instead of sorting or hashing. */
class IndexedParameterMap(val parameterKeys: List<KParameter>, val parameterValues: Array<Any?>)
: AbstractMap<KParameter, Any?>() {
override val entries: Set<Entry<KParameter, Any?>>
get() {
val allPossibleEntries = parameterKeys.mapIndexed { index, value ->
SimpleEntry<KParameter, Any?>(value, parameterValues[index])
}
return allPossibleEntries.filterTo(LinkedHashSet<Entry<KParameter, Any?>>()) {
it.value !== ABSENT_VALUE
}
}
override fun containsKey(key: KParameter) = parameterValues[key.index] !== ABSENT_VALUE
override fun get(key: KParameter): Any? {
val value = parameterValues[key.index]
return if (value !== ABSENT_VALUE) value else null
}
}
}
class KotlinJsonAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi)
: JsonAdapter<*>? {
if (!annotations.isEmpty()) return null
val rawType = Types.getRawType(type)
if (rawType.isInterface) return null
if (rawType.isEnum) return null
if (!rawType.isAnnotationPresent(KOTLIN_METADATA)) return null
if (Util.isPlatformType(rawType)) return null
if (rawType.isLocalClass) {
throw IllegalArgumentException("Cannot serialize local class or object expression ${rawType.name}")
}
val rawTypeKotlin = rawType.kotlin
if (rawTypeKotlin.isAbstract) {
throw IllegalArgumentException("Cannot serialize abstract class ${rawType.name}")
}
if (rawTypeKotlin.isInner) {
throw IllegalArgumentException("Cannot serialize inner class ${rawType.name}")
}
if (rawTypeKotlin.objectInstance != null) {
throw IllegalArgumentException("Cannot serialize object declaration ${rawType.name}")
}
val constructor = rawTypeKotlin.primaryConstructor ?: return null
val parametersByName = constructor.parameters.associateBy { it.name }
constructor.isAccessible = true
val bindingsByName = LinkedHashMap<String, KotlinJsonAdapter.Binding<Any, Any?>>()
for (property in rawTypeKotlin.memberProperties) {
val parameter = parametersByName[property.name]
if (Modifier.isTransient(property.javaField?.modifiers ?: 0)) {
if (parameter != null && !parameter.isOptional) {
throw IllegalArgumentException(
"No default value for transient constructor $parameter")
}
continue
}
if (property !is KMutableProperty1 && parameter == null) continue
property.isAccessible = true
var allAnnotations = property.annotations
var jsonAnnotation = property.findAnnotation<Json>()
if (parameter != null) {
allAnnotations += parameter.annotations
if (jsonAnnotation == null) {
jsonAnnotation = parameter.findAnnotation<Json>()
}
}
val name = jsonAnnotation?.name ?: property.name
val adapter = moshi.adapter<Any>(
property.returnType.javaType, Util.jsonAnnotations(allAnnotations.toTypedArray()))
bindingsByName[property.name] =
KotlinJsonAdapter.Binding(name, adapter, property as KProperty1<Any, Any?>, parameter)
}
val bindings = ArrayList<KotlinJsonAdapter.Binding<Any, Any?>?>()
for (parameter in constructor.parameters) {
val binding = bindingsByName.remove(parameter.name)
if (binding == null && !parameter.isOptional) {
throw IllegalArgumentException("No property for required constructor ${parameter}")
}
bindings += binding
}
bindings += bindingsByName.values
val options = JsonReader.Options.of(*bindings.map { it?.name ?: "\u0000" }.toTypedArray())
return KotlinJsonAdapter(constructor, bindings, options).nullSafe()
}
}

View File

@@ -13,8 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi
package com.squareup.moshi.kotlin
import com.squareup.moshi.FromJson
import com.squareup.moshi.Json
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.Moshi
import com.squareup.moshi.ToJson
import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert.fail
import org.junit.Test
@@ -315,7 +321,7 @@ class KotlinJsonAdapterTest {
} catch (expected: IllegalArgumentException) {
assertThat(expected).hasMessage("No default value for transient constructor parameter #0 " +
"a of fun <init>(kotlin.Int): " +
"com.squareup.moshi.KotlinJsonAdapterTest.RequiredTransientConstructorParameter")
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest.RequiredTransientConstructorParameter")
}
}
@@ -587,7 +593,7 @@ class KotlinJsonAdapterTest {
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessage("No JsonAdapter for interface " +
"com.squareup.moshi.KotlinJsonAdapterTest\$Interface annotated []")
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest\$Interface annotated []")
}
}
@@ -599,8 +605,8 @@ class KotlinJsonAdapterTest {
moshi.adapter(AbstractClass::class.java)
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessage(
"Cannot serialize abstract class com.squareup.moshi.KotlinJsonAdapterTest\$AbstractClass")
assertThat(e).hasMessage("Cannot serialize abstract class " +
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest\$AbstractClass")
}
}
@@ -612,8 +618,8 @@ class KotlinJsonAdapterTest {
moshi.adapter(InnerClass::class.java)
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessage(
"Cannot serialize inner class com.squareup.moshi.KotlinJsonAdapterTest\$InnerClass")
assertThat(e).hasMessage("Cannot serialize inner class " +
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest\$InnerClass")
}
}
@@ -627,7 +633,7 @@ class KotlinJsonAdapterTest {
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessage("Cannot serialize local class or object expression " +
"com.squareup.moshi.KotlinJsonAdapterTest\$localClassesNotSupported\$LocalClass")
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest\$localClassesNotSupported\$LocalClass")
}
}
@@ -638,7 +644,7 @@ class KotlinJsonAdapterTest {
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessage("Cannot serialize object declaration " +
"com.squareup.moshi.KotlinJsonAdapterTest\$ObjectDeclaration")
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest\$ObjectDeclaration")
}
}
@@ -656,7 +662,8 @@ class KotlinJsonAdapterTest {
fail()
} catch (e: IllegalArgumentException) {
assertThat(e).hasMessage("Cannot serialize local class or object expression " +
"com.squareup.moshi.KotlinJsonAdapterTest\$objectExpressionsNotSupported\$expression$1")
"com.squareup.moshi.kotlin.KotlinJsonAdapterTest\$objectExpressionsNotSupported" +
"\$expression$1")
}
}

View File

@@ -33,4 +33,20 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>com.squareup.moshi</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.moshi;
import com.squareup.moshi.internal.Util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
@@ -26,7 +27,7 @@ import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import static com.squareup.moshi.Util.jsonAnnotations;
import static com.squareup.moshi.internal.Util.jsonAnnotations;
final class AdapterMethodsFactory implements JsonAdapter.Factory {
private final List<AdapterMethod> toAdapters;

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.moshi;
import com.squareup.moshi.internal.Util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
@@ -48,7 +49,7 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
if (!(type instanceof Class)) return null;
Class<?> rawType = (Class<?>) type;
if (rawType.isInterface() || rawType.isEnum()) return null;
if (isPlatformType(rawType) && !Types.isAllowedPlatformType(rawType)) {
if (Util.isPlatformType(rawType) && !Types.isAllowedPlatformType(rawType)) {
throw new IllegalArgumentException("Platform "
+ type
+ " annotated "
@@ -83,7 +84,7 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
private void createFieldBindings(
Moshi moshi, Type type, Map<String, FieldBinding<?>> fieldBindings) {
Class<?> rawType = Types.getRawType(type);
boolean platformType = isPlatformType(rawType);
boolean platformType = Util.isPlatformType(rawType);
for (Field field : rawType.getDeclaredFields()) {
if (!includeField(platformType, field.getModifiers())) continue;
@@ -115,19 +116,6 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
}
};
/**
* Returns true if {@code rawType} is built in. We don't reflect on private fields of platform
* types because they're unspecified and likely to be different on Java vs. Android.
*/
static boolean isPlatformType(Class<?> rawType) {
String name = rawType.getName();
return name.startsWith("android.")
|| name.startsWith("java.")
|| name.startsWith("javax.")
|| name.startsWith("kotlin.")
|| name.startsWith("scala.");
}
private final ClassFactory<T> classFactory;
private final FieldBinding<?>[] fieldsArray;
private final JsonReader.Options options;

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.moshi;
import com.squareup.moshi.internal.Util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.moshi;
import com.squareup.moshi.internal.Util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

View File

@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.moshi;
package com.squareup.moshi.internal;
import com.squareup.moshi.JsonQualifier;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Type;
@@ -22,7 +23,7 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
final class Util {
public final class Util {
public static final Set<Annotation> NO_ANNOTATIONS = Collections.emptySet();
private Util() {
@@ -66,4 +67,17 @@ final class Util {
}
return false;
}
/**
* Returns true if {@code rawType} is built in. We don't reflect on private fields of platform
* types because they're unspecified and likely to be different on Java vs. Android.
*/
public static boolean isPlatformType(Class<?> rawType) {
String name = rawType.getName();
return name.startsWith("android.")
|| name.startsWith("java.")
|| name.startsWith("javax.")
|| name.startsWith("kotlin.")
|| name.startsWith("scala.");
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.squareup.moshi;
import com.squareup.moshi.internal.Util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;

View File

@@ -25,7 +25,7 @@ import okio.Buffer;
import org.junit.Test;
import static com.squareup.moshi.TestUtil.newReader;
import static com.squareup.moshi.Util.NO_ANNOTATIONS;
import static com.squareup.moshi.internal.Util.NO_ANNOTATIONS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;

View File

@@ -26,7 +26,7 @@ import org.assertj.core.data.MapEntry;
import org.junit.Test;
import static com.squareup.moshi.TestUtil.newReader;
import static com.squareup.moshi.Util.NO_ANNOTATIONS;
import static com.squareup.moshi.internal.Util.NO_ANNOTATIONS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;

View File

@@ -16,6 +16,7 @@
package com.squareup.moshi;
import android.util.Pair;
import com.squareup.moshi.internal.Util;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;