使用GSON和TypeAdapter将BSON(mongoDB)读入POJO
我正在寻找一种使用GSON将MongoDB文档读入POJO的方法。直到您遇到日期和长整数之类的东西时,它才能正常工作。
我想为Gson写一个自定义适配器,它将转换任何长时间编码的BSON,我创建了自己的适配器:
public class BsonLongTypeAdapter extends TypeAdapter<Long>{
@Override
public void write(JsonWriter out, Long value) throws IOException
{
out.beginObject()
.name("$numberLong")
.value(value.toString())
.endObject();
}
@Override
public Long read(JsonReader in) throws IOException
{
in.beginObject();
assert "$numberLong".equals(in.nextName());
Long value = in.nextLong();
in.endObject();
return value;
}
}
我定义了以下测试来检查是否可行:
@Testpublic void canWriteCorrectJSON() {
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new BsonLongTypeAdapter()).create();
MyTestObject obj = new MyTestObject(1458569479431L);
String gsonString = gson.toJson(obj);
assertEquals("{\"timestamp\":{\"$numberLong\":\"1458569479431\"}}",gsonString);
}
@Test
public void canReadFromJSON() {
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new BsonLongTypeAdapter()).create();
MyTestObject actualTaskObject = gson.fromJson("{\"timestamp\":{\"$numberLong\":\"1458569479431\"}}", MyTestObject.class);
MyTestObject taskObject = new MyTestObject(1458569479431L);
assertEquals(taskObject.getTimestamp(),actualTaskObject.getTimestamp());
}
private static class MyTestObject
{
long timestamp;
public MyTestObject(long ts)
{
timestamp = ts;
}
public long getTimestamp()
{
return timestamp;
}
public void setTimestamp(long timestamp)
{
this.timestamp = timestamp;
}
}
第一个(写)测试工作正常,但是读测试在以下方面失败:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a long but was BEGIN_OBJECT at line 1 column 15 path $.timestamp
因为从未调用过我的适配器的读取功能。我想这可能是因为我想映射到MyTestObject而不是Long,但是我不想为所有包含long的类编写适配器。
是否可以为GSON编写一个适配器,以将我发送的所有BSON长转换为该适配器?
回答:
我使用CustomizedTypeAdapterFactory解决了它。
基本上首先写一个定制的适配器:
public abstract class CustomizedTypeAdapterFactory<C> implements TypeAdapterFactory
{
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
@SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
@Override public void write(JsonWriter out, C value) throws IOException
{
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
@Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {@code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {@code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
然后为所有需要考虑的类创建一个子类。您必须为每个包含long的类创建一个(在这种情况下)。但是除了long值(以及任何其他bson特定值)之外,您无需序列化任何内容
public class MyTestObjectTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyTestObject>{
public MyTestObjectTypeAdapterFactory()
{
super(MyTestObject.class);
}
@Override
protected void beforeWrite(MyTestObject source, JsonElement toSerialize)
{
//you could convert back the other way here, I let mongo's document parser take care of that.
}
@Override
protected void afterRead(JsonElement deserialized)
{
JsonObject timestamp = deserialized.getAsJsonObject().get("timestamp").getAsJsonObject();
deserialized.getAsJsonObject().remove("timestamp");
deserialized.getAsJsonObject().add("timestamp",timestamp.get("$numberLong"));
}
}
然后生成具有以下内容的Gson:
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new MyTestObjectTypeAdapterFactory()).create();
以上是 使用GSON和TypeAdapter将BSON(mongoDB)读入POJO 的全部内容, 来源链接: utcz.com/qa/397422.html