0

I'm having trouble writing a custom serialiser for Json4s to handle the following situation. I have case classes:

trait Condition
case class BasicExpression (field:String, operator:String, value:String) extends Condition
case class BooleanExpression  (val leftExpr: Condition, val logicalOperator:String, 
    val rightExpr: Condition) extends Condition

and I want to be able to read the JSON for both BasicExpression and BooleanExpression using, for example:

var jsonStringBasic:String = """ {"field":"name","operator":"=","value":"adam"}""";
var jsonStringBoolean:String = """{"leftExpr":{"leftExpr":{"field":"field1", "operator":"=", "value":"value1"}, "logicalOperator":"AND", "rightExpr":{"field":"field2","operator":">","value":"500"}}, "logicalOperator":"AND", "rightExpr": {"field":"field3","operator":"<","value":"10000"}}""";
var jValueBasic:JValue = parse(jsonStringBasic, false);
var readCBasic = jValueBasic.extract[Condition];

I understand how the custom serialiser works for reading the BasicExpression, and I could use SimpleTypeHints, but it'd be good to not have to bloat the JSON for every Condition. I could also try extract[BooleanExpression] and if that fails try extract[BasicExpression], but that seems ugly. Is it possible to write the custom serialiser to handle the fact that a BooleanCondition will itself contain another Condition recursively so I can extract[Condition]?

2 Answers2

0

for better parsing JSON you can try this :

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;


public class GsonUtils {

public static String defaultDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ssZ";
private static GsonBuilder gsonBuilder = new GsonBuilder().setDateFormat(defaultDateTimeFormat);

/***
 * Creates a GSON instance from the builder with the default date/time format
 *
 * @return the GSON instance
 */
public static Gson createGson() {
    // Create with default params
    gsonBuilder = gsonBuilder.setDateFormat(defaultDateTimeFormat);
    return gsonBuilder.create();
}

/***
 * Creates a GSON instance from the builder specifying custom date/time format
 *
 * @return the GSON instance
 */
public static Gson createGson(String dateTimeFormat) {
    // Create with the specified dateTimeFormat
    gsonBuilder = gsonBuilder.setDateFormat(dateTimeFormat);
    return gsonBuilder.create();
}

}

and use it like this

  var String = """ {"field":"name","operator":"=","value":"adam"}""";

  Type collectionType = new TypeToken<YOUR_CLASS>() {}.getType();
  YOUR_CLASS iii=  GsonUtils.createGson().fromJson(jsonStringBasic, collectionType);
Irakli
  • 973
  • 3
  • 19
  • 45
  • Thanks for the recommendation - I switched to Gson for a bit but then ran into further issues down the line when Gson doesn't support Scala Lists or Maps, so I went back to Json4s and figured out how to write the serialiser – adambriffett Nov 26 '15 at 14:02
0

Managed to get the CustomSerializer working so it could call itself recursively, in the case of a BooleanExpression, as below:

class ConditionSerialiser extends CustomSerializer[Condition]( format => (

{
    def deserialiseCondition:PartialFunction[JValue, Condition]= {
      case JObject(List(JField("field", JString(field)), JField("operator", JString(operator)), JField("value", JString(value)))) => BasicStringExpression(field, operator, value)
      case JObject(List(JField("field", JString(field)), JField("operator", JString(operator)), JField("value", JInt(value)))) => BasicNumericExpression(field, operator, value.doubleValue)
      case JObject(List(JField("field", JString(field)), JField("operator", JString(operator)), JField("value", JDouble(value)))) => BasicNumericExpression(field, operator, value)
      case JObject(List(JField("leftExpr", leftExpr), JField("logicalOperator", JString(logicalOperator)), JField("rightExpr", rightExpr))) => BooleanExpression(deserialiseCondition(leftExpr), logicalOperator, deserialiseCondition(rightExpr))
    }
    deserialiseCondition
},
{
  case bse: BasicStringExpression => JObject(List(JField("field", JString(bse.field)), JField("operator", JString(bse.operator)), JField("value", JString(bse.value))))       
}
))