/*
* Copyright © 2008, 2012 Pedro Agulló Soliveres.
*
* This file is part of DirectJNgine.
*
* DirectJNgine is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* Commercial use is permitted to the extent that the code/component(s)
* do NOT become part of another Open Source or Commercially developed
* licensed development library or toolkit without explicit permission.
*
* DirectJNgine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with DirectJNgine. If not, see <http://www.gnu.org/licenses/>.
*
* This software uses the ExtJs library (http://extjs.com), which is
* distributed under the GPL v3 license (see http://extjs.com/license).
*/
package com.softwarementors.extjs.djn.router.processor.standard.json;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import clear.djn.DirectOptions;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.softwarementors.extjs.djn.ClassUtils;
import com.softwarementors.extjs.djn.ParallelTask;
import com.softwarementors.extjs.djn.StringUtils;
import com.softwarementors.extjs.djn.Timer;
import com.softwarementors.extjs.djn.UnexpectedException;
import com.softwarementors.extjs.djn.api.RegisteredStandardMethod;
import com.softwarementors.extjs.djn.api.Registry;
import com.softwarementors.extjs.djn.config.GlobalConfiguration;
import com.softwarementors.extjs.djn.gson.JsonDeserializationManager;
import com.softwarementors.extjs.djn.gson.JsonException;
import com.softwarementors.extjs.djn.router.dispatcher.Dispatcher;
import com.softwarementors.extjs.djn.router.processor.RequestException;
import com.softwarementors.extjs.djn.router.processor.standard.StandardErrorResponseData;
import com.softwarementors.extjs.djn.router.processor.standard.StandardRequestProcessorBase;
import com.softwarementors.extjs.djn.router.processor.standard.StandardSuccessResponseData;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
public class JsonRequestProcessor extends StandardRequestProcessorBase {
/* Will not release this until extensive testings is performed */
private final static boolean SUPPORTS_OBJECT_TYPE_PARAMETER = false;
@NonNull private static final Logger logger = Logger.getLogger( JsonRequestProcessor.class);
// We need a globally unique thread-pool, not a pool per processor!
@CheckForNull private static volatile ExecutorService individualRequestsThreadPool;
@NonNull private JsonParser parser = new JsonParser();
protected JsonParser getJsonParser() {
return this.parser;
}
@edu.umd.cs.findbugs.annotations.SuppressWarnings( value="NP_NONNULL_RETURN_VIOLATION",
justification="This method will never return null, because if the value it should return is null on entry, it assigns it first")
private ExecutorService getIndividualRequestsThreadPool() {
synchronized (JsonRequestProcessor.class) {
if( individualRequestsThreadPool == null ) {
individualRequestsThreadPool = createThreadPool();
}
return individualRequestsThreadPool;
}
}
private ExecutorService createThreadPool() {
assert getGlobalConfiguration() != null;
ExecutorService result = new ThreadPoolExecutor( getGlobalConfiguration().getBatchRequestsMinThreadsPoolSize(),
getGlobalConfiguration().getBatchRequestsMaxThreadsPoolSize(),
getGlobalConfiguration().getBatchRequestsThreadKeepAliveSeconds(),
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
return result;
}
public JsonRequestProcessor(Registry registry, Dispatcher dispatcher, GlobalConfiguration globalConfiguration) {
super(registry, dispatcher, globalConfiguration);
}
public String process(Reader reader, Writer writer) throws IOException {
String requestString = IOUtils.toString(reader);
if( logger.isDebugEnabled() ) {
logger.debug( "Request data (JSON)=>" + requestString );
}
JsonRequestData[] requests = getIndividualJsonRequests( requestString );
final boolean isBatched = requests.length > 1;
if( isBatched ) {
if( logger.isDebugEnabled() ) {
logger.debug( "Batched request: " + requests.length + " individual requests batched");
}
}
Collection<String> responses = null;
boolean useMultipleThreadsIfBatched = isBatched && getGlobalConfiguration().getBatchRequestsMultithreadingEnabled();
if( useMultipleThreadsIfBatched ) {
responses = processIndividualRequestsInMultipleThreads( requests);
}
else {
responses = processIndividualRequestsInThisThread(requests);
}
String result = convertInvididualResponsesToJsonString( responses);
writer.write( result );
if( logger.isDebugEnabled() ) {
logger.debug( "ResponseData data (JSON)=>" + result );
}
return result;
}
private Collection<String> processIndividualRequestsInThisThread(JsonRequestData[] requests) {
Collection<String> responses;
boolean isBatched = requests.length > 1;
responses = new ArrayList<String>(requests.length);
int requestNumber = 1;
for( JsonRequestData request : requests ) {
String response = processIndividualRequest( request, isBatched, requestNumber );
responses.add( response );
requestNumber++;
}
return responses;
}
private Collection<String> processIndividualRequestsInMultipleThreads( JsonRequestData[] requests) {
assert requests != null;
int individualRequestNumber = 1;
Collection<Callable<String>> tasks = new ArrayList<Callable<String>>(requests.length);
for (final JsonRequestData request : requests) {
JsonRequestProcessorThread thread = createJsonRequestProcessorThread();
thread.initialize(this, request, individualRequestNumber);
tasks.add(thread);
individualRequestNumber++;
}
try {
ParallelTask<String> task = new ParallelTask<String>(
getIndividualRequestsThreadPool(), tasks, getGlobalConfiguration().getBatchRequestsMaxThreadsPerRequest());
Collection<String> responses = task.get();
return responses;
}
catch (InterruptedException e) {
List<String> responses = new ArrayList<String>(requests.length);
logger.error( "(Controlled) server error cancelled a batch of " + requests.length + " individual requests due to an InterruptedException exception. " + e.getMessage(), e);
for (final JsonRequestData request : requests) {
StandardErrorResponseData response = createJsonServerErrorResponse(request, e);
responses.add(getGson().toJson(response));
}
return responses;
}
catch (ExecutionException e) {
UnexpectedException ex = UnexpectedException.forExecutionExceptionShouldNotHappenBecauseProcessorHandlesExceptionsAsServerErrorResponses(e);
logger.error( ex.getMessage(), ex );
throw ex;
}
}
private JsonRequestProcessorThread createJsonRequestProcessorThread() {
Class<? extends JsonRequestProcessorThread> cls = getGlobalConfiguration().getJsonRequestProcessorThreadClass();
try {
return cls.newInstance();
}
catch (InstantiationException e) {
JsonRequestProcessorThreadConfigurationException ex = JsonRequestProcessorThreadConfigurationException.forUnableToInstantiateJsonRequestProcessorThread(cls, e);
logger.fatal( ex.getMessage(), ex);
throw ex;
}
catch (IllegalAccessException e) {
JsonRequestProcessorThreadConfigurationException ex = JsonRequestProcessorThreadConfigurationException.forUnableToInstantiateJsonRequestProcessorThread(cls, e);
logger.fatal( ex.getMessage(), ex);
throw ex;
}
}
private JsonRequestData[] getIndividualJsonRequests( String requestString ) {
assert !StringUtils.isEmpty(requestString);
JsonObject[] individualJsonRequests = parseIndividualJsonRequests(requestString, getJsonParser());
JsonRequestData[] individualRequests = new JsonRequestData[individualJsonRequests.length];
int i = 0;
for( JsonObject individualRequest : individualJsonRequests ) {
individualRequests[i] = createIndividualJsonRequest(individualRequest);
i++;
}
return individualRequests;
}
private static String convertInvididualResponsesToJsonString(Collection<String> responses) {
assert responses != null;
assert !responses.isEmpty();
StringBuilder result = new StringBuilder();
if( responses.size() > 1 ) {
result.append( "[\n" );
}
int j = 0;
for( String response : responses ) {
result.append(response);
boolean isLast = j == responses.size() - 1;
if( !isLast) {
result.append( ",");
}
j++;
}
if( responses.size() > 1 ) {
result.append( "]");
}
return result.toString();
}
private Object[] getIndividualRequestParameters(JsonRequestData request) {
assert request != null;
RegisteredStandardMethod method = getStandardMethod( request.getAction(), request.getMethod());
assert method != null;
Object[] parameters;
if( !method.getHandleParametersAsJsonArray()) {
checkJsonMethodParameterTypes( request.getJsonData(), method );
parameters = jsonDataToMethodParameters(method, request.getJsonData(), method.getParameterTypes(), method.getGsonParameterTypes() );
}
else {
parameters = new Object[] { request.getJsonData() };
}
return parameters;
}
private Object[] jsonDataToMethodParameters(RegisteredStandardMethod method, JsonArray jsonParametersArray, Class<?>[] parameterTypes, Type[] gsonParameterTypes) {
assert method != null;
assert parameterTypes != null;
try {
JsonElement[] jsonParameters = getJsonElements(jsonParametersArray);
Object[] result = getMethodParameters(method, jsonParameters);
return result;
}
catch( JsonParseException ex ) {
throw JsonException.forFailedConversionFromJsonStringToMethodParameters( method, jsonParametersArray.toString(), parameterTypes, gsonParameterTypes, ex);
}
}
private static JsonElement[] getJsonElements(JsonArray jsonParameters) {
if( jsonParameters == null ) {
return new JsonElement[] {};
}
JsonElement[] parameters;
JsonArray dataArray = jsonParameters;
parameters = new JsonElement[dataArray.size()];
for( int i = 0; i < dataArray.size(); i++ ) {
parameters[i] = dataArray.get(i);
}
return parameters;
}
private static boolean isString( JsonElement element ) {
assert element != null;
return element.isJsonPrimitive() && ((JsonPrimitive)element).isString();
}
private Object[] getMethodParameters(RegisteredStandardMethod method , JsonElement[] jsonParameters) {
assert method != null;
assert jsonParameters != null;
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] result = new Object[jsonParameters.length];
for( int i = 0; i < jsonParameters.length; i++ ) {
JsonElement jsonValue = jsonParameters[i];
Class<?> parameterType = parameterTypes[i];
Object value = null;
Type gsonType = null;
if( method.getGsonParameterTypes() != null ) {
gsonType = method.getGsonParameterTypes()[i];
}
value = jsonToJavaObject(jsonValue, parameterType, gsonType);
result[i] = value;
}
return result;
}
private @CheckForNull Object jsonToJavaObject(JsonElement jsonValue, Class<?> parameterType, Type gsonType) {
Object value;
if( jsonValue.isJsonNull() ) {
return null;
}
// Handle string in a special way, due to possibility of having a Java char type in the Java
// side
if( isString(jsonValue)) {
if( parameterType.equals(String.class)) {
value = jsonValue.getAsString();
return value;
}
if(parameterType.equals(char.class) || parameterType.equals( Character.class) ) {
value = Character.valueOf(jsonValue.getAsString().charAt(0));
return value;
}
}
// If Java parameter is Object, we perform 'magic': json string, number, boolean and
// null are converted to Java String, Double, Boolean and null. For json objects,
// we create a Map<String,Object>, and for json arrays an Object[], and then perform
// internal object conversion recursively using the same technique
if( parameterType.equals( Object.class ) && SUPPORTS_OBJECT_TYPE_PARAMETER) {
value = toSimpleJavaType(jsonValue);
return value;
}
// If the Java parameter is an array, but we are receiving a single item, we try to convert
// the item to a single item array so that the Java method can digest it
boolean useCustomGsonType = gsonType != null;
boolean fakeJsonArrayForManyValuedClasses = JsonDeserializationManager.isManyValuedClass(parameterType) && !jsonValue.isJsonArray();
Type typeToInstantiate = parameterType;
if( useCustomGsonType ) {
typeToInstantiate = gsonType;
}
JsonElement json = jsonValue;
if( fakeJsonArrayForManyValuedClasses ) {
JsonArray fakeJson = new JsonArray();
fakeJson.add(jsonValue);
json = fakeJson;
}
value = getGson().fromJson(json, typeToInstantiate);
return value;
}
private @CheckForNull Object toSimpleJavaType(JsonElement jsonValue) {
if (jsonValue==null) return null; //VR
Object value = null;
if( !jsonValue.isJsonNull() ) {
if( jsonValue.isJsonPrimitive()) {
JsonPrimitive primitive = jsonValue.getAsJsonPrimitive();
if( primitive.isBoolean()) {
value = Boolean.valueOf( primitive.getAsBoolean() );
}
else if( primitive.isNumber()) {
value = Double.valueOf(primitive.getAsDouble());
}
else if( primitive.isString()) {
value = primitive.getAsString();
}
else {
throw UnexpectedException.forUnexpectedCodeBranchExecuted();
}
}
else if( jsonValue.isJsonArray()) {
//This simply does not work (?)
JsonArray array = jsonValue.getAsJsonArray();
Object[] result = new Object[array.size()];
for( int i = 0; i < array.size(); i++ ) {
result[i] = toSimpleJavaType(array.get(i));
}
value = result;
}
else if( jsonValue.isJsonObject() ) {
//This simply does not work (?)
//value = getGson().fromJson(jsonValue, Map.class );
JsonObject obj = jsonValue.getAsJsonObject();
Iterator<Entry<String,JsonElement>> properties = obj.entrySet().iterator();
Map<String, Object> result = new HashMap<String,Object>();
while( properties.hasNext() ) {
Entry<String,JsonElement> property = properties.next();
JsonElement propertyValue = property.getValue();
result.put( property.getKey(), toSimpleJavaType(propertyValue));
}
value = result;
}
else {
throw UnexpectedException.forUnexpectedCodeBranchExecuted();
}
}
return value;
}
private static JsonElement[] getIndividualRequestJsonParameters(JsonArray jsonParameters) {
if( jsonParameters == null ) {
return new JsonElement[] {};
}
JsonElement[] parameters;
parameters = new JsonElement[jsonParameters.size()];
for( int i = 0; i < jsonParameters.size(); i++ ) {
parameters[i] = jsonParameters.get(i);
}
return parameters;
}
private static void checkJsonMethodParameterTypes(JsonArray jsonData, RegisteredStandardMethod method) {
assert method != null;
JsonElement[] jsonParameters = getIndividualRequestJsonParameters( jsonData );
Class<?>[] parameterTypes = method.getParameterTypes();
assert jsonParameters.length == parameterTypes.length;
for( int i = 0; i < parameterTypes.length; i++ ) {
Class<?> parameterType = parameterTypes[i];
JsonElement jsonElement = jsonParameters[i];
if( !isValidJsonTypeForJavaType(jsonElement, parameterType )) {
throw new IllegalArgumentException( "'" + jsonElement.toString() + "' is not a valid json text for the '" + parameterType.getName() + "' Java type");
}
}
}
private static boolean isValidJsonTypeForJavaType(JsonElement jsonElement, Class<?> parameterType) {
assert jsonElement != null;
assert parameterType != null;
// Check json nulls
if( jsonElement.isJsonNull() ) {
return !parameterType.isPrimitive();
}
if( parameterType.isArray() ) {
// This is *always* ok because if the value is not a json array
// we will instantiate a single item array and attempt conversion
return true;
}
if( parameterType.equals( Boolean.class ) || parameterType.equals( boolean.class ) ) {
return jsonElement.isJsonPrimitive() && ((JsonPrimitive)jsonElement).isBoolean();
}
else if( parameterType.equals( char.class ) || parameterType.equals( Character.class ) ) {
if( jsonElement.isJsonPrimitive() && ((JsonPrimitive)jsonElement).isString() ) {
return jsonElement.getAsString().length() == 1;
}
return false;
}
else if( parameterType.equals( String.class ) ) {
return jsonElement.isJsonPrimitive() && ((JsonPrimitive)jsonElement).isString();
}
else if( ClassUtils.isNumericType(parameterType)) {
return jsonElement.isJsonPrimitive() && ((JsonPrimitive)jsonElement).isNumber();
}
// If we arrived here, assume somebody will know how to handle the json element, maybe customizing Gson's serialization
return true;
}
/* package */ String processIndividualRequest( JsonRequestData request, boolean isBatched, int requestNumber ) {
assert request != null;
boolean resultReported = false;
Timer timer = new Timer();
try {
if( isBatched ) {
if( logger.isDebugEnabled() ) {
logger.debug( " - Individual request #" + requestNumber + " request data=>" + getGson().toJson(request) );
}
}
Object[] parameters = getIndividualRequestParameters( request);
String action = request.getAction();
String method = request.getMethod();
StandardSuccessResponseData response = new StandardSuccessResponseData( request.getTid(), action, method);
JsonDeserializationManager mgr = JsonDeserializationManager.getManager();
try {
//VR BEGIN
getDirectOptions(request);
//VR END
Object result = dispatchStandardMethod(action, method, parameters);
mgr.friendOnlyAccess_setRoot(result);
response.setResult(result);
String json = getGson().toJson(response);
if( isBatched ) {
if( logger.isDebugEnabled() ) {
timer.stop();
timer.logDebugTimeInMilliseconds( " - Individual request #" + requestNumber + " response data=>" + json );
resultReported = true;
}
}
return json;
}
finally {
mgr.friendOnlyAccess_dispose(); // Cleanup in case we are reusing thread
}
}
catch( Exception t ) {
StandardErrorResponseData response = createJsonServerErrorResponse(request, t);
String json = getGson().toJson(response);
logger.error( "(Controlled) server error: " + t.getMessage() + " for Method '" + request.getFullMethodName() + "'", t);
return json;
}
finally {
if( !resultReported ) {
timer.stop();
// No point in logging individual requests when the request is not batched
if( isBatched ) {
if( logger.isDebugEnabled() ) {
timer.logDebugTimeInMilliseconds( " - Individual request #" + requestNumber + ": " + request.getFullMethodName() + ". Time");
}
}
}
}
}
//VR BEGIN
private void getDirectOptions(JsonRequestData request) {
@SuppressWarnings("unchecked")
Map<String,Object> directOptions = (Map<String,Object>)toSimpleJavaType(request.getJsonDirectOptions());
DirectOptions.setOptions(directOptions);
Double d = (Double) DirectOptions.getOption("start");
if (d!=null) DirectOptions.setOption("start", new Integer(d.intValue()));
d = (Double) DirectOptions.getOption("limit");
if (d!=null) DirectOptions.setOption("limit", new Integer(d.intValue()));
d = (Double) DirectOptions.getOption("page");
if (d!=null) DirectOptions.setOption("page", new Integer(d.intValue()));
}
@SuppressWarnings("unchecked")
protected Object dispatchStandardMethod( String actionName, String methodName, Object[] parameters ) {
Object records = super.dispatchStandardMethod(actionName, methodName, parameters);
@SuppressWarnings("rawtypes")
Map resultMap = null;
if (records instanceof List<?>) {
if (DirectOptions.getOption("total")!=null) {
resultMap = new HashMap();
resultMap.put("success", true);
resultMap.put("total", DirectOptions.getOption("total"));
resultMap.put("records", records);
}
}
return (resultMap!=null)? resultMap:records;
}
//VR END
private static JsonObject[] parseIndividualJsonRequests(String requestString, JsonParser parser) {
assert !StringUtils.isEmpty(requestString);
assert parser != null;
JsonObject[] individualRequests;
JsonElement root = parser.parse( requestString );
if( root.isJsonArray() ) {
JsonArray rootArray = (JsonArray)root;
if( rootArray.size() == 0 ) {
RequestException ex = RequestException.forRequestBatchMustHaveAtLeastOneRequest();
logger.error( ex.getMessage(), ex );
throw ex;
}
individualRequests = new JsonObject[rootArray.size()];
int i = 0;
for( JsonElement item : rootArray ) {
if( !item.isJsonObject()) {
RequestException ex = RequestException.forRequestBatchItemMustBeAValidJsonObject(i);
logger.error( ex.getMessage(), ex );
throw ex;
}
individualRequests[i] = (JsonObject)item;
i++;
}
}
else if( root.isJsonObject() ) {
individualRequests = new JsonObject[] {(JsonObject)root};
}
else {
RequestException ex = RequestException.forRequestMustBeAValidJsonObjectOrArray();
logger.error( ex.getMessage(), ex );
throw ex;
}
return individualRequests;
}
private static JsonRequestData createIndividualJsonRequest( JsonObject element ) {
assert element != null;
String action = getNonEmptyJsonString( element, JsonRequestData.ACTION_ELEMENT );
String method = getNonEmptyJsonString( element, JsonRequestData.METHOD_ELEMENT );
Long tid = getNonEmptyJsonLong( element, JsonRequestData.TID_ELEMENT );
String type = getNonEmptyJsonString( element, JsonRequestData.TYPE_ELEMENT );
JsonArray jsonData = getMethodParametersJsonData(element);
// VR BEGIN
JsonObject jsonOptions = getMethodParametersJsonOptions(element);
JsonRequestData result = new JsonRequestData( type, action, method, tid, jsonData, jsonOptions );
// VR END
return result;
}
@CheckForNull private static JsonArray getMethodParametersJsonData(JsonObject object) {
assert object != null;
JsonElement data = object.get(JsonRequestData.DATA_ELEMENT);
if( data == null ) {
RequestException ex = RequestException.forJsonElementMissing(JsonRequestData.DATA_ELEMENT);
logger.error( ex.getMessage(), ex );
throw ex;
}
if( data.isJsonNull()) {
return null;
}
if( !data.isJsonNull() && !data.isJsonArray()) {
RequestException ex = RequestException.forJsonElementMustBeAJsonArray(JsonRequestData.DATA_ELEMENT, data.toString());
logger.error( ex.getMessage(), ex );
throw ex;
}
return (JsonArray)data;
}
/*
* VR BEGIN
*/
@CheckForNull private static JsonObject getMethodParametersJsonOptions(JsonObject object) {
assert object != null;
JsonElement options = object.get(JsonRequestData.OPTIONS_ELEMENT);
if (( options != null )&&!options.isJsonNull()) {
if( !options.isJsonObject()) {
RequestException ex = RequestException.forRequestMustBeAValidJsonObjectOrArray();
logger.error( ex.getMessage(), ex );
throw ex;
}
}
return (JsonObject)options;
}
/*
* END
*/
private static <T> T getNonEmptyJsonPrimitiveValue( JsonObject object, String elementName, PrimitiveJsonValueGetter<T> getter ) {
assert object != null;
assert !StringUtils.isEmpty(elementName);
try {
JsonElement element = object.get( elementName );
if( element == null ) {
RequestException ex = RequestException.forJsonElementMissing(elementName);
logger.error( ex.getMessage(), ex );
throw ex;
}
// Take into account that the element must be a primitive, and then a string!
T result = null;
if( element.isJsonPrimitive() ) {
result = getter.checkedGet( (JsonPrimitive) element );
}
if( result == null ) {
RequestException ex = RequestException.forJsonElementMustBeANonNullOrEmptyValue(elementName, getter.getValueType() );
logger.error( ex.getMessage(), ex );
throw ex;
}
return result;
}
catch( JsonParseException e ) {
String message = "Probably a DirectJNgine BUG: there should not be JSON parse exceptions: we should have checked ALL error conditions. " + e.getMessage();
logger.error( message, e );
assert false : message;
throw e; // Just to make the compiler happy -because of the assert
}
}
// A simple interface that helps us avoid duplicated code
// Its purpose is to retrieve a primitive value, or null
// if the primitive value is null or "empty" (makes sense for strings...)
interface PrimitiveJsonValueGetter<T> {
// Must return null if the specified primitive is not of type T or is "empty"
@CheckForNull T checkedGet( JsonPrimitive value );
Class<T> getValueType();
}
private static class PrimitiveJsonLongGetter implements PrimitiveJsonValueGetter<Long> {
public Long checkedGet(JsonPrimitive value) {
assert value != null;
if( value.isNumber() ) {
String v = value.toString();
try {
return Long.valueOf( Long.parseLong(v) );
}
catch( NumberFormatException ex ) {
return null;
}
}
return null;
}
public Class<Long> getValueType() {
return Long.class;
}
}
private static class PrimitiveJsonStringGetter implements PrimitiveJsonValueGetter<String> {
// @Override
public String checkedGet(JsonPrimitive value) {
assert value != null;
if( value.isString() ) {
String result = value.getAsString();
if( result.equals("") )
result = null;
return result;
}
return null;
}
// @Override
public Class<String> getValueType() {
return String.class;
}
}
private static Long getNonEmptyJsonLong( JsonObject object, String elementName ) {
assert object != null;
assert !StringUtils.isEmpty(elementName);
return getNonEmptyJsonPrimitiveValue( object, elementName, new PrimitiveJsonLongGetter() );
}
private static String getNonEmptyJsonString( JsonObject object, String elementName ) {
assert object != null;
assert !StringUtils.isEmpty(elementName);
return getNonEmptyJsonPrimitiveValue( object, elementName, new PrimitiveJsonStringGetter() );
}
}