使用Scala和Play Framework将自定义类型的映射序列化为JSON

时间:2014-09-23 13:59:01

标签: json scala serialization playframework

我使用http://www.blaenkdenum.com/notes/play/

中的信息创建了自定义类型的地图
def getAllProductsWithStockItems: Map[Product, List[StockItem]] = {
        DB.withConnection { implicit connection =>
        val sql = SQL("select p.*, s.*" +
        "from products p" +
        "inner join stock_items s on (p.id = s.product_id)")

        val results: List[(Product, StockItem)] = sql.as(productStockItemParser *)

    results.groupBy { _._1 }.mapValues { _.map { _._2 } }
    }
}

我需要将Map[Product, List[StockItem]]序列化/反序列化为JSON,但我真的不知道该怎么做。我已经为自定义类型(Product和StockItem)提供了有效的序列化程序,我使用Play的本机JSON库进行编码,但如果它更好,我可以使用另一个。有人可以给我一些指示吗?


更新:List / StockItem示例不是很好,但它只是一个抽象。最后,我有一个代表1到n关系的结构。 因此,考虑到每个产品都有一个StockItem列表,我希望JSON看起来像这样:

{
"products": [
            {
                "id": 1
                "productName": "coffee",
                "stockitems": [   
                               {
                                   "id":1,
                                   "brandName": "Crazycoffee",
                                   "price": 5
                                   "quantity": 3000
                               },
                               {
                                   "id":2,
                                   "brandName": "Badcoffee",
                                   "price": 1
                                   "quantity": 2000
                               }
                               ]
            },
            {
                "id": 1
                "productName": "ice cream",
                "stockitems": [   
                               {
                                   "id":1,
                                   "brandName": "Sleazyice",
                                   "price": 2
                                   "quantity": 300
                               }
                               ]
            }
            ]
}

2 个答案:

答案 0 :(得分:0)

我还没有对它进行过测试,但它是从我工作的java代码中编写的。使用杰克逊图书馆(包括在游戏2中):

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;

public static String toJson(Map<Product, List<StockItem>> lst)
{
    JsonFactory factory = new JsonFactory();
    CharArrayWriter writer = new CharArrayWriter();
    try{
        JsonGenerator gen = factory.createGenerator(writer);
        gen.writeStartObject();
        gen.writeFieldName("infos");
        gen.writeRaw(":" + listToJson(lst));
        gen.writeEndObject();
        gen.close();
    }catch(Throwable e){
        Logger.error("AjaxRequest.generateResponse: " + e.getMessage());
        e.printStackTrace();
    }
    return new String(writer.toCharArray());
}

/**
 * Convert a list into a json string.
 */
public static String listToJson(List<?> lst) throws IOException
{
    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = new JsonFactory();
    CharArrayWriter writer = new CharArrayWriter();
    JsonGenerator gen = factory.createGenerator(writer);
    gen.writeRaw(mapper.writeValueAsString(lst));
    gen.close();
    return new String(writer.toCharArray());
}

杰克逊图书馆工作得很好,但目前还不容易理解。无论如何,经过很少的修改,这段代码应该可行。

答案 1 :(得分:0)

你可以考虑使用https://playframework.com/documentation/2.5.x/ScalaJsonAutomated,那么你可以节省一些时间,而不必手动编写所有的作家和读者。你可以创建一个&#34;包装器&#34;基于您的顶级JSON元素的实体&#34;产品&#34;例如ProductsList(例如)。以下是您可以执行此操作的示例:

case class ProductList (
  list: Vector[Product]
)

object ProductList {

  /**
    * Mapping to and from JSON.
    */
  implicit val documentFormatter: Format[ProductList] = (
    (__ \ "products").format[Vector[Product]]
  ) (ProductList.apply, unlift(ProductList.unapply))

}