mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 07:59:21 +08:00
Convert MapJsonAdapter to Kotlin (#1492)
* Rename .java to .kt * Convert MapJsonAdapter to Kotlin * Pull up factory into companion object * Spotless * apicmp * Use knownNotNull * Use a template
This commit is contained in:
@@ -35,7 +35,8 @@ val japicmp = tasks.register<JapicmpTask>("japicmp") {
|
|||||||
"com.squareup.moshi.JsonAdapter#indent(java.lang.String)" // Was unintentionally open before
|
"com.squareup.moshi.JsonAdapter#indent(java.lang.String)" // Was unintentionally open before
|
||||||
)
|
)
|
||||||
fieldExcludes = listOf(
|
fieldExcludes = listOf(
|
||||||
"com.squareup.moshi.CollectionJsonAdapter#FACTORY" // False-positive, class is not public anyway
|
"com.squareup.moshi.CollectionJsonAdapter#FACTORY", // False-positive, class is not public anyway
|
||||||
|
"com.squareup.moshi.MapJsonAdapter#FACTORY" // Class is not public
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of comparable keys to values. Unlike {@code TreeMap}, this class uses insertion order for
|
* A map of comparable keys to values. Unlike {@code TreeMap}, this class uses insertion order for
|
||||||
@@ -90,7 +91,7 @@ final class LinkedHashTreeMap<K, V> extends AbstractMap<K, V> implements Seriali
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V put(K key, V value) {
|
public V put(K key, @Nullable V value) {
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
throw new NullPointerException("key == null");
|
throw new NullPointerException("key == null");
|
||||||
}
|
}
|
||||||
|
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* https://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.io.IOException;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts maps with string keys to JSON objects.
|
|
||||||
*
|
|
||||||
* <p>TODO: support maps with other key types and convert to/from strings.
|
|
||||||
*/
|
|
||||||
final class MapJsonAdapter<K, V> extends JsonAdapter<Map<K, V>> {
|
|
||||||
public static final Factory FACTORY =
|
|
||||||
new Factory() {
|
|
||||||
@Override
|
|
||||||
public @Nullable JsonAdapter<?> create(
|
|
||||||
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
|
||||||
if (!annotations.isEmpty()) return null;
|
|
||||||
Class<?> rawType = Types.getRawType(type);
|
|
||||||
if (rawType != Map.class) return null;
|
|
||||||
Type[] keyAndValue = Types.mapKeyAndValueTypes(type, rawType);
|
|
||||||
return new MapJsonAdapter<>(moshi, keyAndValue[0], keyAndValue[1]).nullSafe();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final JsonAdapter<K> keyAdapter;
|
|
||||||
private final JsonAdapter<V> valueAdapter;
|
|
||||||
|
|
||||||
MapJsonAdapter(Moshi moshi, Type keyType, Type valueType) {
|
|
||||||
this.keyAdapter = moshi.adapter(keyType);
|
|
||||||
this.valueAdapter = moshi.adapter(valueType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void toJson(JsonWriter writer, Map<K, V> map) throws IOException {
|
|
||||||
writer.beginObject();
|
|
||||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
|
||||||
if (entry.getKey() == null) {
|
|
||||||
throw new JsonDataException("Map key is null at " + writer.getPath());
|
|
||||||
}
|
|
||||||
writer.promoteValueToName();
|
|
||||||
keyAdapter.toJson(writer, entry.getKey());
|
|
||||||
valueAdapter.toJson(writer, entry.getValue());
|
|
||||||
}
|
|
||||||
writer.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<K, V> fromJson(JsonReader reader) throws IOException {
|
|
||||||
LinkedHashTreeMap<K, V> result = new LinkedHashTreeMap<>();
|
|
||||||
reader.beginObject();
|
|
||||||
while (reader.hasNext()) {
|
|
||||||
reader.promoteNameToValue();
|
|
||||||
K name = keyAdapter.fromJson(reader);
|
|
||||||
V value = valueAdapter.fromJson(reader);
|
|
||||||
V replaced = result.put(name, value);
|
|
||||||
if (replaced != null) {
|
|
||||||
throw new JsonDataException(
|
|
||||||
"Map key '"
|
|
||||||
+ name
|
|
||||||
+ "' has multiple values at path "
|
|
||||||
+ reader.getPath()
|
|
||||||
+ ": "
|
|
||||||
+ replaced
|
|
||||||
+ " and "
|
|
||||||
+ value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reader.endObject();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "JsonAdapter(" + keyAdapter + "=" + valueAdapter + ")";
|
|
||||||
}
|
|
||||||
}
|
|
73
moshi/src/main/java/com/squareup/moshi/MapJsonAdapter.kt
Normal file
73
moshi/src/main/java/com/squareup/moshi/MapJsonAdapter.kt
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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 com.squareup.moshi.internal.knownNotNull
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts maps with string keys to JSON objects.
|
||||||
|
*
|
||||||
|
* TODO: support maps with other key types and convert to/from strings.
|
||||||
|
*/
|
||||||
|
internal class MapJsonAdapter<K, V>(moshi: Moshi, keyType: Type, valueType: Type) : JsonAdapter<Map<K, V?>>() {
|
||||||
|
private val keyAdapter: JsonAdapter<K> = moshi.adapter(keyType)
|
||||||
|
private val valueAdapter: JsonAdapter<V> = moshi.adapter(valueType)
|
||||||
|
|
||||||
|
override fun toJson(writer: JsonWriter, map: Map<K, V?>?) {
|
||||||
|
writer.beginObject()
|
||||||
|
// Never null because we wrap in nullSafe()
|
||||||
|
for ((key, value) in knownNotNull(map)) {
|
||||||
|
if (key == null) {
|
||||||
|
throw JsonDataException("Map key is null at " + writer.path)
|
||||||
|
}
|
||||||
|
writer.promoteValueToName()
|
||||||
|
keyAdapter.toJson(writer, key)
|
||||||
|
valueAdapter.toJson(writer, value)
|
||||||
|
}
|
||||||
|
writer.endObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromJson(reader: JsonReader): Map<K, V?> {
|
||||||
|
val result = LinkedHashTreeMap<K, V?>()
|
||||||
|
reader.beginObject()
|
||||||
|
while (reader.hasNext()) {
|
||||||
|
reader.promoteNameToValue()
|
||||||
|
val name = keyAdapter.fromJson(reader) ?: throw JsonDataException("Map key is null at ${reader.path}")
|
||||||
|
val value = valueAdapter.fromJson(reader)
|
||||||
|
val replaced = result.put(name, value)
|
||||||
|
if (replaced != null) {
|
||||||
|
throw JsonDataException(
|
||||||
|
"Map key '$name' has multiple values at path ${reader.path}: $replaced and $value"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.endObject()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString() = "JsonAdapter($keyAdapter=$valueAdapter)"
|
||||||
|
|
||||||
|
companion object Factory : JsonAdapter.Factory {
|
||||||
|
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
|
||||||
|
if (annotations.isNotEmpty()) return null
|
||||||
|
val rawType = type.rawType
|
||||||
|
if (rawType != Map::class.java) return null
|
||||||
|
val keyAndValue = Types.mapKeyAndValueTypes(type, rawType)
|
||||||
|
return MapJsonAdapter<Any, Any>(moshi, keyAndValue[0], keyAndValue[1]).nullSafe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -366,7 +366,7 @@ public class Moshi internal constructor(builder: Builder) {
|
|||||||
val BUILT_IN_FACTORIES: List<JsonAdapter.Factory> = buildList(6) {
|
val BUILT_IN_FACTORIES: List<JsonAdapter.Factory> = buildList(6) {
|
||||||
add(StandardJsonAdapters)
|
add(StandardJsonAdapters)
|
||||||
add(CollectionJsonAdapter.Factory)
|
add(CollectionJsonAdapter.Factory)
|
||||||
add(MapJsonAdapter.FACTORY)
|
add(MapJsonAdapter.Factory)
|
||||||
add(ArrayJsonAdapter.FACTORY)
|
add(ArrayJsonAdapter.FACTORY)
|
||||||
add(RecordJsonAdapter.FACTORY)
|
add(RecordJsonAdapter.FACTORY)
|
||||||
add(ClassJsonAdapter.FACTORY)
|
add(ClassJsonAdapter.FACTORY)
|
||||||
|
@@ -262,7 +262,7 @@ public final class MapJsonAdapterTest {
|
|||||||
@SuppressWarnings("unchecked") // It's the caller's responsibility to make sure K and V match.
|
@SuppressWarnings("unchecked") // It's the caller's responsibility to make sure K and V match.
|
||||||
private <K, V> JsonAdapter<Map<K, V>> mapAdapter(Type keyType, Type valueType) {
|
private <K, V> JsonAdapter<Map<K, V>> mapAdapter(Type keyType, Type valueType) {
|
||||||
return (JsonAdapter<Map<K, V>>)
|
return (JsonAdapter<Map<K, V>>)
|
||||||
MapJsonAdapter.FACTORY.create(
|
MapJsonAdapter.Factory.create(
|
||||||
Types.newParameterizedType(Map.class, keyType, valueType), NO_ANNOTATIONS, moshi);
|
Types.newParameterizedType(Map.class, keyType, valueType), NO_ANNOTATIONS, moshi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user