Micronaut 用 Jackson 進(jìn)行 JSON 綁定

2023-03-06 14:46 更新

現(xiàn)在最常見(jiàn)的數(shù)據(jù)交換格式是 JSON。

實(shí)際上,Controller 注解中的默認(rèn)值指定 Micronaut 中的控制器默認(rèn)使用和生成 JSON。

為了以非阻塞方式執(zhí)行此操作,Micronaut 構(gòu)建在 Jackson 異步 JSON 解析 API 和 Netty 之上,以便以非阻塞方式讀取傳入的 JSON。

使用 Reactive Frameworks 綁定

然而,從開(kāi)發(fā)人員的角度來(lái)看,您通常可以只使用普通舊式 Java 對(duì)象 (POJO),并且可以選擇使用 Reactive 框架,例如 RxJava 或 Project Reactor。下面是一個(gè)控制器的例子,它以非阻塞的方式從 JSON 中讀取并保存?zhèn)魅氲?nbsp;POJO:

使用 Reactive Streams 讀取 JSON

 Java Groovy  Kotlin 
@Controller("/people")
public class PersonController {

    Map<String, Person> inMemoryDatastore = new ConcurrentHashMap<>();

@Post("/saveReactive")
@SingleResult
public Publisher<HttpResponse<Person>> save(@Body Publisher<Person> person) { // (1)
    return Mono.from(person).map(p -> {
                inMemoryDatastore.put(p.getFirstName(), p); // (2)
                return HttpResponse.created(p); // (3)
            }
    );
}

}
@Controller("/people")
class PersonController {

    Map<String, Person> inMemoryDatastore = new ConcurrentHashMap<>()

@Post("/saveReactive")
@SingleResult
Publisher<HttpResponse<Person>> save(@Body Publisher<Person> person) { // (1)
    Mono.from(person).map({ p ->
        inMemoryDatastore.put(p.getFirstName(), p) // (2)
        HttpResponse.created(p) // (3)
    })
}

}
@Controller("/people")
class PersonController {

    internal var inMemoryDatastore: MutableMap<String, Person> = ConcurrentHashMap()

@Post("/saveReactive")
@SingleResult
fun save(@Body person: Publisher<Person>): Publisher<HttpResponse<Person>> { // (1)
    return Mono.from(person).map { p ->
        inMemoryDatastore[p.firstName] = p // (2)
        HttpResponse.created(p) // (3)
    }
}

}
  1. 該方法接收一個(gè)發(fā)布者,一旦讀取 JSON,該發(fā)布者就會(huì)發(fā)出 POJO

  2. map 方法將實(shí)例存儲(chǔ)在 Map 中

  3. 返回一個(gè) HttpResponse

從命令行使用 cURL,您可以將 JSON POST 到 /people URI:

使用 cURL POST JSON

$ curl -X POST localhost:8080/people -d '{"firstName":"Fred","lastName":"Flintstone","age":45}'

使用 CompletableFuture 綁定

與前面示例相同的方法也可以改用 CompletableFuture API 編寫(xiě):

使用 CompletableFuture 讀取 JSON

 Java Groovy  Kotlin 
@Controller("/people")
public class PersonController {

    Map<String, Person> inMemoryDatastore = new ConcurrentHashMap<>();

@Post("/saveFuture")
public CompletableFuture<HttpResponse<Person>> save(@Body CompletableFuture<Person> person) {
    return person.thenApply(p -> {
                inMemoryDatastore.put(p.getFirstName(), p);
                return HttpResponse.created(p);
            }
    );
}

}
@Controller("/people")
class PersonController {

    Map<String, Person> inMemoryDatastore = new ConcurrentHashMap<>()

@Post("/saveFuture")
CompletableFuture<HttpResponse<Person>> save(@Body CompletableFuture<Person> person) {
    person.thenApply({ p ->
        inMemoryDatastore.put(p.getFirstName(), p)
        HttpResponse.created(p)
    })
}

}
@Controller("/people")
class PersonController {

    internal var inMemoryDatastore: MutableMap<String, Person> = ConcurrentHashMap()

@Post("/saveFuture")
fun save(@Body person: CompletableFuture<Person>): CompletableFuture<HttpResponse<Person>> {
    return person.thenApply { p ->
        inMemoryDatastore[p.firstName] = p
        HttpResponse.created(p)
    }
}

}

上面的例子使用thenApply方法實(shí)現(xiàn)的和前面的例子一樣。

使用 POJO 進(jìn)行綁定

但是請(qǐng)注意,您可以輕松地編寫(xiě):

綁定 JSON POJO

 Java Groovy  Kotlin 
@Controller("/people")
public class PersonController {

    Map<String, Person> inMemoryDatastore = new ConcurrentHashMap<>();

@Post
public HttpResponse<Person> save(@Body Person person) {
    inMemoryDatastore.put(person.getFirstName(), person);
    return HttpResponse.created(person);
}

}
@Controller("/people")
class PersonController {

    Map<String, Person> inMemoryDatastore = new ConcurrentHashMap<>()

@Post
HttpResponse<Person> save(@Body Person person) {
    inMemoryDatastore.put(person.getFirstName(), person)
    HttpResponse.created(person)
}

}
@Controller("/people")
class PersonController {

    internal var inMemoryDatastore: MutableMap<String, Person> = ConcurrentHashMap()

@Post
fun save(@Body person: Person): HttpResponse<Person> {
    inMemoryDatastore[person.firstName] = person
    return HttpResponse.created(person)
}

}

只有在以非阻塞方式讀取數(shù)據(jù)后,Micronaut 才會(huì)執(zhí)行您的方法。

Jackson 產(chǎn)生的輸出可以通過(guò)多種方式定制,從定義 Jackson 模塊到使用 Jackson 注釋

Jackson 配置

可以通過(guò)使用 JacksonConfiguration 類(lèi)進(jìn)行配置來(lái)配置 Jackson ObjectMapper。

所有 Jackson 配置鍵都以 jackson 開(kāi)頭。

dateFormat

String

日期格式

locale

String

使用 Locale.forLanguageTag。例子: en-US

timeZone

String

使用 TimeZone.getTimeZone。例子: PST

serializationInclusion

String

JsonInclude.Include 之一。例子: ALWAYS

propertyNamingStrategy

String

PropertyNamingStrategy 實(shí)例的名稱(chēng)。例子: SNAKE_CASE

defaultTyping

String

用于枚舉 ObjectMapper.DefaultTyping 的多態(tài)類(lèi)型處理的全局 defaultTyping。例子: NON_FINAL

示例:

 Properties Yaml  Toml  Groovy  Hocon  JSON 
jackson.serializationInclusion=ALWAYS
jackson:
  serializationInclusion: ALWAYS
[jackson]
  serializationInclusion="ALWAYS"
jackson {
  serializationInclusion = "ALWAYS"
}
{
  jackson {
    serializationInclusion = "ALWAYS"
  }
}
{
  "jackson": {
    "serializationInclusion": "ALWAYS"
  }
}

特性

所有功能都可以配置為它們的名稱(chēng)作為鍵和一個(gè)布爾值來(lái)指示啟用或禁用。

serialization

Map

SerializationFeature

deserialization

Map

DeserializationFeature

mapper

Map

MapperFeature

parser

Map

JsonParser.Feature

generator

Map

JsonGenerator.Feature

factory

Map

JsonFactory.Feature

示例:

 Properties Yaml  Toml  Groovy  Hocon  JSON 
jackson.serialization.indentOutput=true
jackson.serialization.writeDatesAsTimestamps=false
jackson.deserialization.useBigIntegerForInts=true
jackson.deserialization.failOnUnknownProperties=false
jackson:
  serialization:
    indentOutput: true
    writeDatesAsTimestamps: false
  deserialization:
    useBigIntegerForInts: true
    failOnUnknownProperties: false
[jackson]
  [jackson.serialization]
    indentOutput=true
    writeDatesAsTimestamps=false
  [jackson.deserialization]
    useBigIntegerForInts=true
    failOnUnknownProperties=false
jackson {
  serialization {
    indentOutput = true
    writeDatesAsTimestamps = false
  }
  deserialization {
    useBigIntegerForInts = true
    failOnUnknownProperties = false
  }
}
{
  jackson {
    serialization {
      indentOutput = true
      writeDatesAsTimestamps = false
    }
    deserialization {
      useBigIntegerForInts = true
      failOnUnknownProperties = false
    }
  }
}
{
  "jackson": {
    "serialization": {
      "indentOutput": true,
      "writeDatesAsTimestamps": false
    },
    "deserialization": {
      "useBigIntegerForInts": true,
      "failOnUnknownProperties": false
    }
  }
}

進(jìn)一步自定義 JsonFactory

在某些情況下,您可能希望在功能配置之外自定義 ObjectMapper 使用的 JsonFactory(例如,允許自定義字符轉(zhuǎn)義)。這可以通過(guò)提供您自己的 JsonFactory bean 或通過(guò)提供在啟動(dòng)時(shí)配置默認(rèn) bean 的 BeanCreatedEventListener<JsonFactory> 來(lái)實(shí)現(xiàn)。

支持@JsonView

如果在配置文件(例如 application.yml)中將 jackson.json-view.enabled 設(shè)置為 true,則可以在控制器方法上使用 @JsonView 注釋。

Jackson 的 @JsonView 注釋允許您控制在每個(gè)響應(yīng)的基礎(chǔ)上公開(kāi)哪些屬性。

Beans

除了配置之外,還可以注冊(cè) bean 來(lái)自定義 Jackson。擴(kuò)展以下任何類(lèi)的所有 bean 都在對(duì)象映射器中注冊(cè):

服務(wù)加載器

通過(guò)服務(wù)加載器注冊(cè)的任何模塊也將添加到默認(rèn)對(duì)象映射器。

數(shù)字精度

在 JSON 解析期間,框架可能會(huì)將任何傳入數(shù)據(jù)轉(zhuǎn)換為中間對(duì)象模型。默認(rèn)情況下,此模型使用 BigInteger、long 和 double 作為數(shù)值。這意味著可能會(huì)丟失一些可以由 BigDecimal 表示的信息。例如,即使反序列化的目標(biāo)類(lèi)型使用 BigDecimal,也可能會(huì)截?cái)嗖荒苡?nbsp;double 表示的具有許多小數(shù)位的數(shù)字。關(guān)于尾隨零數(shù)的元數(shù)據(jù) (BigDecimal.precision()),例如0.12 和 0.120 之間的差異也被丟棄。

如果您需要數(shù)字類(lèi)型的完全準(zhǔn)確性,請(qǐng)使用以下配置:

 Properties Yaml  Toml  Groovy  Hocon  JSON 
jackson.deserialization.useBigIntegerForInts=true
jackson.deserialization.useBigDecimalForFloats=true
jackson:
  deserialization:
    useBigIntegerForInts: true
    useBigDecimalForFloats: true
[jackson]
  [jackson.deserialization]
    useBigIntegerForInts=true
    useBigDecimalForFloats=true
jackson {
  deserialization {
    useBigIntegerForInts = true
    useBigDecimalForFloats = true
  }
}
{
  jackson {
    deserialization {
      useBigIntegerForInts = true
      useBigDecimalForFloats = true
    }
  }
}
{
  "jackson": {
    "deserialization": {
      "useBigIntegerForInts": true,
      "useBigDecimalForFloats": true
    }
  }
}


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)