mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
Adapter methods.
This is a fun new API that could make writing JSON adapters much easier.
This commit is contained in:
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
// TODO: support qualifier annotations.
|
||||||
|
// TODO: support @Nullable
|
||||||
|
// TODO: path in JsonWriter.
|
||||||
|
|
||||||
|
final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
||||||
|
private final Map<Type, ToAdapter> toAdapters;
|
||||||
|
private final Map<Type, FromAdapter> fromAdapters;
|
||||||
|
|
||||||
|
AdapterMethodsFactory(Map<Type, ToAdapter> toAdapters, Map<Type, FromAdapter> fromAdapters) {
|
||||||
|
this.toAdapters = toAdapters;
|
||||||
|
this.fromAdapters = fromAdapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, final Moshi moshi) {
|
||||||
|
final ToAdapter toAdapter = toAdapters.get(type);
|
||||||
|
final FromAdapter fromAdapter = fromAdapters.get(type);
|
||||||
|
if (toAdapter == null && fromAdapter == null) return null;
|
||||||
|
|
||||||
|
final JsonAdapter<Object> delegate = toAdapter == null || fromAdapter == null
|
||||||
|
? moshi.nextAdapter(this, type, annotations)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return new JsonAdapter<Object>() {
|
||||||
|
@Override public void toJson(JsonWriter writer, Object value) throws IOException {
|
||||||
|
if (toAdapter == null) {
|
||||||
|
delegate.toJson(writer, value);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
toAdapter.toJson(moshi, writer, value);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
if (e.getCause() instanceof IOException) throw (IOException) e.getCause();
|
||||||
|
throw new JsonDataException(e.getCause().getMessage()); // TODO: more context?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Object fromJson(JsonReader reader) throws IOException {
|
||||||
|
if (fromAdapter == null) {
|
||||||
|
return delegate.fromJson(reader);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return fromAdapter.fromJson(moshi, reader);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
if (e.getCause() instanceof IOException) throw (IOException) e.getCause();
|
||||||
|
throw new JsonDataException(e.getCause().getMessage()); // TODO: more context?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdapterMethodsFactory get(Object adapter) {
|
||||||
|
Map<Type, ToAdapter> toAdapters = new LinkedHashMap<>();
|
||||||
|
Map<Type, FromAdapter> fromAdapters = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (Class<?> c = adapter.getClass(); c != Object.class; c = c.getSuperclass()) {
|
||||||
|
for (Method m : c.getDeclaredMethods()) {
|
||||||
|
if (m.isAnnotationPresent(ToJson.class)) {
|
||||||
|
ToAdapter toAdapter = toAdapter(adapter, m);
|
||||||
|
ToAdapter replaced = toAdapters.put(toAdapter.type, toAdapter);
|
||||||
|
if (replaced != null) {
|
||||||
|
throw new IllegalArgumentException("Conflicting @ToJson methods:\n"
|
||||||
|
+ " " + replaced.method + "\n"
|
||||||
|
+ " " + toAdapter.method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.isAnnotationPresent(FromJson.class)) {
|
||||||
|
FromAdapter fromAdapter = fromAdapter(adapter, m);
|
||||||
|
FromAdapter replaced = fromAdapters.put(fromAdapter.type, fromAdapter);
|
||||||
|
if (replaced != null) {
|
||||||
|
throw new IllegalArgumentException("Conflicting @FromJson methods:\n"
|
||||||
|
+ " " + replaced.method + "\n"
|
||||||
|
+ " " + fromAdapter.method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toAdapters.isEmpty() && fromAdapters.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Expected at least one @ToJson or @FromJson method on "
|
||||||
|
+ adapter.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AdapterMethodsFactory(toAdapters, fromAdapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object that calls a {@code method} method on {@code adapter} in service of
|
||||||
|
* converting an object to JSON.
|
||||||
|
*/
|
||||||
|
static ToAdapter toAdapter(Object adapter, Method method) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||||
|
final Type returnType = method.getGenericReturnType();
|
||||||
|
|
||||||
|
if (parameterTypes.length == 2
|
||||||
|
&& parameterTypes[0] == JsonWriter.class
|
||||||
|
&& returnType == void.class) {
|
||||||
|
return new ToAdapter(parameterTypes[1], adapter, method) {
|
||||||
|
@Override public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
||||||
|
throws IOException, InvocationTargetException, IllegalAccessException {
|
||||||
|
method.invoke(adapter, writer, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} else if (parameterTypes.length == 1 && returnType != void.class) {
|
||||||
|
return new ToAdapter(parameterTypes[0], adapter, method) {
|
||||||
|
@Override public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
||||||
|
throws IOException, InvocationTargetException, IllegalAccessException {
|
||||||
|
JsonAdapter<Object> delegate = moshi.adapter(returnType, method);
|
||||||
|
Object intermediate = method.invoke(adapter, value);
|
||||||
|
delegate.toJson(writer, intermediate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unexpected signature for " + method + ".\n"
|
||||||
|
+ "@ToJson method signatures may have one of the following structures:\n"
|
||||||
|
+ " <any access modifier> void toJson(JsonWriter writer, T value) throws <any>;\n"
|
||||||
|
+ " <any access modifier> R toJson(T value) throws <any>;\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class ToAdapter {
|
||||||
|
final Type type;
|
||||||
|
final Object adapter;
|
||||||
|
final Method method;
|
||||||
|
|
||||||
|
public ToAdapter(Type type, Object adapter, Method method) {
|
||||||
|
this.type = type;
|
||||||
|
this.adapter = adapter;
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void toJson(Moshi moshi, JsonWriter writer, Object value)
|
||||||
|
throws IOException, IllegalAccessException, InvocationTargetException;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object that calls a {@code method} method on {@code adapter} in service of
|
||||||
|
* converting an object from JSON.
|
||||||
|
*/
|
||||||
|
static FromAdapter fromAdapter(Object adapter, Method method) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
final Type[] parameterTypes = method.getGenericParameterTypes();
|
||||||
|
final Type returnType = method.getGenericReturnType();
|
||||||
|
|
||||||
|
if (parameterTypes.length == 1
|
||||||
|
&& parameterTypes[0] == JsonReader.class
|
||||||
|
&& returnType != void.class) {
|
||||||
|
// public Point pointFromJson(JsonReader jsonReader) throws Exception {
|
||||||
|
return new FromAdapter(returnType, adapter, method) {
|
||||||
|
@Override public Object fromJson(Moshi moshi, JsonReader reader)
|
||||||
|
throws IOException, IllegalAccessException, InvocationTargetException {
|
||||||
|
return method.invoke(adapter, reader);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} else if (parameterTypes.length == 1 && returnType != void.class) {
|
||||||
|
// public Point pointFromJson(List<Integer> o) throws Exception {
|
||||||
|
return new FromAdapter(returnType, adapter, method) {
|
||||||
|
@Override public Object fromJson(Moshi moshi, JsonReader reader)
|
||||||
|
throws IOException, IllegalAccessException, InvocationTargetException {
|
||||||
|
JsonAdapter<Object> delegate = moshi.adapter(parameterTypes[0]);
|
||||||
|
Object intermediate = delegate.fromJson(reader);
|
||||||
|
return method.invoke(adapter, intermediate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unexpected signature for " + method + ".\n"
|
||||||
|
+ "@ToJson method signatures may have one of the following structures:\n"
|
||||||
|
+ " <any access modifier> void toJson(JsonWriter writer, T value) throws <any>;\n"
|
||||||
|
+ " <any access modifier> R toJson(T value) throws <any>;\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class FromAdapter {
|
||||||
|
final Type type;
|
||||||
|
final Object adapter;
|
||||||
|
final Method method;
|
||||||
|
|
||||||
|
public FromAdapter(Type type, Object adapter, Method method) {
|
||||||
|
this.type = type;
|
||||||
|
this.adapter = adapter;
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Object fromJson(Moshi moshi, JsonReader reader)
|
||||||
|
throws IOException, IllegalAccessException, InvocationTargetException;
|
||||||
|
}
|
||||||
|
}
|
26
moshi/src/main/java/com/squareup/moshi/FromJson.java
Normal file
26
moshi/src/main/java/com/squareup/moshi/FromJson.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface FromJson {
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/** Thrown when a JSON document doesn't match the expected format. */
|
||||||
|
public final class JsonDataException extends RuntimeException {
|
||||||
|
public JsonDataException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonDataException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonDataException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
@@ -131,6 +131,10 @@ public final class Moshi {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder add(Object adapter) {
|
||||||
|
return add(AdapterMethodsFactory.get(adapter));
|
||||||
|
}
|
||||||
|
|
||||||
public Moshi build() {
|
public Moshi build() {
|
||||||
return new Moshi(this);
|
return new Moshi(this);
|
||||||
}
|
}
|
||||||
|
26
moshi/src/main/java/com/squareup/moshi/ToJson.java
Normal file
26
moshi/src/main/java/com/squareup/moshi/ToJson.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface ToJson {
|
||||||
|
}
|
201
moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java
Normal file
201
moshi/src/test/java/com/squareup/moshi/AdapterMethodsTest.java
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public final class AdapterMethodsTest {
|
||||||
|
@Test public void toAndFromJsonViaListOfIntegers() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new PointAsListOfIntegersJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<Point> pointAdapter = moshi.adapter(Point.class);
|
||||||
|
assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("[5,8]");
|
||||||
|
assertThat(pointAdapter.fromJson("[5,8]")).isEqualTo(new Point(5, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PointAsListOfIntegersJsonAdapter {
|
||||||
|
@ToJson List<Integer> pointToJson(Point point) {
|
||||||
|
return Arrays.asList(point.x, point.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson Point pointFromJson(List<Integer> o) throws Exception {
|
||||||
|
if (o.size() != 2) throw new Exception("Expected 2 elements but was " + o);
|
||||||
|
return new Point(o.get(0), o.get(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void toAndFromJsonWithWriterAndReader() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new PointWriterAndReaderJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<Point> pointAdapter = moshi.adapter(Point.class);
|
||||||
|
assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("[5,8]");
|
||||||
|
assertThat(pointAdapter.fromJson("[5,8]")).isEqualTo(new Point(5, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PointWriterAndReaderJsonAdapter {
|
||||||
|
@ToJson void pointToJson(JsonWriter writer, Point point) throws IOException {
|
||||||
|
writer.beginArray();
|
||||||
|
writer.value(point.x);
|
||||||
|
writer.value(point.y);
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson Point pointFromJson(JsonReader reader) throws Exception {
|
||||||
|
reader.beginArray();
|
||||||
|
int x = reader.nextInt();
|
||||||
|
int y = reader.nextInt();
|
||||||
|
reader.endArray();
|
||||||
|
return new Point(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void toJsonOnly() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new PointAsListOfIntegersToAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<Point> pointAdapter = moshi.adapter(Point.class);
|
||||||
|
assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("[5,8]");
|
||||||
|
assertThat(pointAdapter.fromJson("{\"x\":5,\"y\":8}")).isEqualTo(new Point(5, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PointAsListOfIntegersToAdapter {
|
||||||
|
@ToJson List<Integer> pointToJson(Point point) {
|
||||||
|
return Arrays.asList(point.x, point.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void fromJsonOnly() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new PointAsListOfIntegersFromAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<Point> pointAdapter = moshi.adapter(Point.class);
|
||||||
|
assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("{\"x\":5,\"y\":8}");
|
||||||
|
assertThat(pointAdapter.fromJson("[5,8]")).isEqualTo(new Point(5, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PointAsListOfIntegersFromAdapter {
|
||||||
|
@FromJson Point pointFromJson(List<Integer> o) throws Exception {
|
||||||
|
if (o.size() != 2) throw new Exception("Expected 2 elements but was " + o);
|
||||||
|
return new Point(o.get(0), o.get(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void multipleLayersOfAdapters() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new MultipleLayersJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<Point> pointAdapter = moshi.adapter(Point.class).lenient();
|
||||||
|
assertThat(pointAdapter.toJson(new Point(5, 8))).isEqualTo("\"5 8\"");
|
||||||
|
assertThat(pointAdapter.fromJson("\"5 8\"")).isEqualTo(new Point(5, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MultipleLayersJsonAdapter {
|
||||||
|
@ToJson List<Integer> pointToJson(Point point) {
|
||||||
|
return Arrays.asList(point.x, point.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToJson String integerListToJson(List<Integer> list) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (Integer i : list) {
|
||||||
|
if (result.length() != 0) result.append(" ");
|
||||||
|
result.append(i.intValue());
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson Point pointFromJson(List<Integer> o) throws Exception {
|
||||||
|
if (o.size() != 2) throw new Exception("Expected 2 elements but was " + o);
|
||||||
|
return new Point(o.get(0), o.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson List<Integer> listOfIntegersFromJson(String list) throws Exception {
|
||||||
|
List<Integer> result = new ArrayList<>();
|
||||||
|
for (String part : list.split(" ")) {
|
||||||
|
result.add(Integer.parseInt(part));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void conflictingToAdapters() throws Exception {
|
||||||
|
Moshi.Builder builder = new Moshi.Builder();
|
||||||
|
try {
|
||||||
|
builder.add(new ConflictingsToJsonAdapter());
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertThat(expected.getMessage()).contains(
|
||||||
|
"Conflicting @ToJson methods:", "pointToJson1", "pointToJson2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ConflictingsToJsonAdapter {
|
||||||
|
@ToJson List<Integer> pointToJson1(Point point) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToJson String pointToJson2(Point point) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void conflictingFromAdapters() throws Exception {
|
||||||
|
Moshi.Builder builder = new Moshi.Builder();
|
||||||
|
try {
|
||||||
|
builder.add(new ConflictingsFromJsonAdapter());
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertThat(expected.getMessage()).contains(
|
||||||
|
"Conflicting @FromJson methods:", "pointFromJson1", "pointFromJson2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ConflictingsFromJsonAdapter {
|
||||||
|
@FromJson Point pointFromJson1(List<Integer> point) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson Point pointFromJson2(String point) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Point {
|
||||||
|
final int x;
|
||||||
|
final int y;
|
||||||
|
|
||||||
|
public Point(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean equals(Object o) {
|
||||||
|
return o instanceof Point && ((Point) o).x == x && ((Point) o).y == y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int hashCode() {
|
||||||
|
return x * 37 + y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user