Как преобразовать список Scala [org.bson.Document] в строку JSON?

У меня была функция в AWS Lambda:

def test(pj: Pojo, context: Context): java.util.List[Document]

который вообще не инициализировал pj входными значениями JSON.

Я нашел другой способ использования AWS Lambda в Scala вот так:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

val scalaMapper = new ObjectMapper().registerModule(new DefaultScalaModule)

def test(input: InputStream, output: OutputStream): Unit = {
  val inputPojo = scalaMapper.readValue(input, classOf[Pojo])
  val answer: Seq[Document] = getTheRealAnswer(inputPojo)
  val jsonStr = "{ frustration: \"I wish my answer was JSON.\" }"
  output.write(jsonStr.getBytes("UTF-8"))
}

и это работает, за исключением того, что я действительно хочу вернуть в качестве ответа, это массив документов JSON. Как мне это сделать?

Изменить: в моем исходном сообщении я написал: "[первый пример] возвращал ответ как ошибку 22. В основном AWS (я думаю) обрабатывал преобразование JSON списка [документ] ] в качестве имени файла, JSON имеет множество двоеточий, а ошибка 22 возникла из-за того, что двоеточия в именах файлов недопустимы. Странно ». Это оказалось ошибкой при вызове функции AWS Lambda из интерфейса командной строки AWS. Я пропустил имя выходного файла в вызове команды, а возвращенный JSON интерпретировался AWS CLI как имя файла.


person gknauth    schedule 24.03.2016    source источник
comment
Можете ли вы поделиться своим классом Pojo? существует ли getTheRealAnswer? Вы упоминаете org.bson.Document, но не понимаете, какие звонки монго и что еще может быть задействовано. Какую библиотеку вы используете для подключения к mongo?   -  person Barry    schedule 24.03.2016
comment
@Barry, с тех пор, как я написал это сообщение, у меня все должно было работать так: def jsonizePoints (cDocument: Seq [Document]): String = {val sb = new StringBuilder; for (doc ‹- cDocument) {if (sb.nonEmpty) {sb.append (,)} sb.append (doc.toJson)} sb.toString}   -  person gknauth    schedule 24.03.2016
comment
Извините за этот большой неформатированный беспорядок кода в комментарии, но в основном я jsonized каждый элемент Seq и использовал StringBuilder для разделения элементов запятыми.   -  person gknauth    schedule 24.03.2016
comment
Что касается ошибки 22 вверху, это был PEBCAK. Я вызывал лямбда-функции aws из командной строки, я не указал выходной файл, а интерфейс командной строки AWS, по-видимому, взял мой вывод JSON и сказал: «Это ваше имя файла?»   -  person gknauth    schedule 24.03.2016
comment
@Barry: это класс Pojo: case BoundingBox (swLon: Float, swLat: Float, neLon: Float, neLat: Float)   -  person gknauth    schedule 24.03.2016
comment
Мне удалось инициализировать Pojo [BoundingBox], используя второй метод, который я описал выше, но не используя первый метод.   -  person gknauth    schedule 24.03.2016
comment
Да, getTheRealAnswer существует, но он называется по-другому, у меня он упакован в JAR. Обычно вы вызываете функцию с ограничивающей рамкой, и поиск выполняется в MongoDB, и вы получаете обратно Seq [Document].   -  person gknauth    schedule 24.03.2016


Ответы (2)


С тех пор, как я написал это сообщение, у меня все работало следующим образом:

def jsonizeDocs(cDocument: Seq[Document]): String = {
  val sb=new StringBuilder
  for (doc <- cDocument) {
    if (sb.nonEmpty) {
      sb.append(",")
    }
    sb.append(doc.toJson)
  }
  sb.toString
}
person gknauth    schedule 27.03.2016

Примечание! Этот ответ основан на легкой оболочке, которую я написал для json4s, которая Я вызываю расширения JSON

Предполагая, что вы используете объекты Scala, импортируйте io.onema.json.Extensions._

import io.onema.json.Extensions._

case class Doc(title: String, content: String)

val listOfDocs = Seq(Doc("Foo", "bar"), Doc("Bar", "Baz"), Doc("Blah", "Bax"))
val json: String = listOfDocs.asJson
println(json)  
// [{"title":"Foo","content":"bar"},{"title":"Bar","content":"Baz"},{"title":"Blah","content":"Bax"}]

См. рабочий пример здесь

Теперь, когда вы используете Pojo, вам нужно импортировать io.onema.json.JavaExtensions._. Предполагая, что у вас есть следующий POJO:

public class Document {
 private String title;
 private String content;
 public String getTitle() {return title;}
 public String getContent() {return content;}
 public void setTitle(String title) { this.title = title;}
 public void setContent(String content) {this.content = content;}
}

Используйте этот метод в своем коде Scala следующим образом:

import io.onema.json.JavaExtensions._
import com.example.Document

// ...

def jsonizeDocs(cDocument: Seq[Document]): String = {
  val json: String = cDocument.asJson
  println(json)
  json
}

В AWS Lambda (и наоборот) используйте jsonDecode и настраиваемый сопоставитель объектов для десериализации до ожидаемого типа:

import io.onema.json.JavaExtensions._
import io.onema.json.Mapper
import com.example.Document

val jsonString = """[{"title":"Foo","content":"bar"},{"title":"Bar","content":"Baz"},{"title":"Blah","content":"Bax"}]"""
val mapper: ObjectMapper = Mapper.allowUnknownPropertiesMapper
val doc: Document = jsonString.jsonDecode[Document](mapper)

Я довольно успешно использовал описанный здесь метод в лямбда-фреймворке, который может десериализоваться в лямбда-события AWS, а также в пользовательские типы, см. простой пример здесь.

Вот и все! вы можете использовать эту библиотеку или один из множества сериализаторов JSON в Java или Scala. Если вы знаете тип своих объектов, большинство библиотек позволит вам очень легко сериализовать в JSON и обратно.

person Onema    schedule 05.02.2019