/*
* Copyright (C) 2010-2012 Paul Watts (paulcwatts@gmail.com)
* and individual contributors.
*
* 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 org.onebusaway.android.io;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.node.TreeTraversingParser;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
public class JacksonSerializer implements ObaApi.SerializationHandler {
private static final String TAG = "JacksonSerializer";
private static class SingletonHolder {
public static final JacksonSerializer INSTANCE = new JacksonSerializer();
}
private static final ObjectMapper mMapper = new ObjectMapper();
static {
mMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mMapper.setVisibilityChecker(
VisibilityChecker.Std.defaultInstance()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY));
}
private JacksonSerializer() { /* singleton */ }
/**
* Make the singleton instance available
*/
public static ObaApi.SerializationHandler getInstance() {
return SingletonHolder.INSTANCE;
}
private static JsonParser getJsonParser(Reader reader)
throws IOException {
TreeTraversingParser parser = new TreeTraversingParser(mMapper.readTree(reader));
parser.setCodec(mMapper);
return parser;
}
public String toJson(String input) {
TextNode node = JsonNodeFactory.instance.textNode(input);
return node.toString();
}
@Override
public <T> T createFromError(Class<T> cls, int code, String error) {
// This is not very efficient, but it's an error case and it's easier
// than instantiating one ourselves.
final String jsonErr = toJson(error);
final String json = getErrorJson(code, jsonErr);
try {
// Hopefully this never returns null or throws.
return mMapper.readValue(json, cls);
} catch (JsonParseException e) {
Log.e(TAG, e.toString());
} catch (JsonMappingException e) {
Log.e(TAG, e.toString());
} catch (IOException e) {
Log.e(TAG, e.toString());
}
return null;
}
private String getErrorJson(int code, final String jsonErr) {
return String.format("{\"code\": %d,\"version\":\"2\",\"text\":%s}", code, jsonErr);
}
public <T> T deserialize(Reader reader, Class<T> cls) {
try {
T t = getJsonParser(reader).readValueAs(cls);
if (t == null) {
// TODO: test switching from Gson for errors
t = createFromError(cls, ObaApi.OBA_INTERNAL_ERROR, "Json error");
}
return t;
} catch (FileNotFoundException e) {
return createFromError(cls, ObaApi.OBA_NOT_FOUND, e.toString());
} catch (JsonProcessingException e) {
return createFromError(cls, ObaApi.OBA_INTERNAL_ERROR, e.toString());
} catch (IOException e) {
return createFromError(cls, ObaApi.OBA_IO_EXCEPTION, e.toString());
}
}
public <T> T deserializeFromResponse(String response, Class<T> cls) {
try {
return mMapper.readValue(response, cls);
} catch (JsonParseException e) {
Log.e(TAG, e.toString());
} catch (JsonMappingException e) {
Log.e(TAG, e.toString());
} catch (IOException e) {
Log.e(TAG, e.toString());
}
return null;
}
public String serialize(Object obj) {
StringWriter writer = new StringWriter();
JsonGenerator jsonGenerator;
try {
jsonGenerator = new MappingJsonFactory().createJsonGenerator(writer);
mMapper.writeValue(jsonGenerator, obj);
return writer.toString();
} catch (JsonGenerationException e) {
Log.e(TAG, e.toString());
return getErrorJson(ObaApi.OBA_INTERNAL_ERROR, e.toString());
} catch (JsonMappingException e) {
Log.e(TAG, e.toString());
return getErrorJson(ObaApi.OBA_INTERNAL_ERROR, e.toString());
} catch (IOException e) {
Log.e(TAG, e.toString());
return getErrorJson(ObaApi.OBA_IO_EXCEPTION, e.toString());
}
}
}