mirror of
https://github.com/fankes/moshi.git
synced 2025-10-18 23:49: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
|
||||
)
|
||||
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.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* 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
|
||||
public V put(K key, V value) {
|
||||
public V put(K key, @Nullable V value) {
|
||||
if (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) {
|
||||
add(StandardJsonAdapters)
|
||||
add(CollectionJsonAdapter.Factory)
|
||||
add(MapJsonAdapter.FACTORY)
|
||||
add(MapJsonAdapter.Factory)
|
||||
add(ArrayJsonAdapter.FACTORY)
|
||||
add(RecordJsonAdapter.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.
|
||||
private <K, V> JsonAdapter<Map<K, V>> mapAdapter(Type keyType, Type valueType) {
|
||||
return (JsonAdapter<Map<K, V>>)
|
||||
MapJsonAdapter.FACTORY.create(
|
||||
MapJsonAdapter.Factory.create(
|
||||
Types.newParameterizedType(Map.class, keyType, valueType), NO_ANNOTATIONS, moshi);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user