如何将 jackson 中的 @JsonAnySetter 转换为 circe
how to convert @JsonAnySetter in jackson to circe
我正在重写一些 java 代码,这些代码使用 jackson json 解析为 scala circe。
javaDevice
class是这个-
package forjava;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({"ua", "dnt", "ip", "devicetype"})
public class Device implements Serializable {
@JsonProperty("ua")
private String ua;
@JsonProperty("dnt")
private Integer dnt;
@JsonProperty("ip")
private String ip;
@JsonProperty("devicetype")
private Integer devicetype;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap();
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
private static final long serialVersionUID = -4938649324295079141L;
public Device() {
}
public Device(String ua, Integer dnt, Integer lmt, String ip, String ipv6, Integer devicetype, String make) {
this.ua = ua;
this.dnt = dnt;
this.ip = ip;
this.devicetype = devicetype;
}
@JsonProperty("ua")
public String getUa() {
return this.ua;
}
@JsonProperty("ua")
public void setUa(String ua) {
this.ua = ua;
}
@JsonProperty("dnt")
public Integer getDnt() {
return this.dnt;
}
@JsonProperty("dnt")
public void setDnt(Integer dnt) {
this.dnt = dnt;
}
@JsonProperty("ip")
public String getIp() {
return this.ip;
}
@JsonProperty("ip")
public void setIp(String ip) {
this.ip = ip;
}
@JsonProperty("devicetype")
public Integer getDevicetype() {
return this.devicetype;
}
@JsonProperty("devicetype")
public void setDevicetype(Integer devicetype) {
this.devicetype = devicetype;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(Device.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
sb.append("ua");
sb.append('=');
sb.append(this.ua == null ? "<null>" : this.ua);
sb.append(',');
sb.append("dnt");
sb.append('=');
sb.append(this.dnt == null ? "<null>" : this.dnt);
sb.append(',');
sb.append("ip");
sb.append('=');
sb.append(this.ip == null ? "<null>" : this.ip);
sb.append(',');
sb.append("devicetype");
sb.append('=');
sb.append(this.devicetype == null ? "<null>" : this.devicetype);
sb.append(',');
sb.append("additionalProperties");
sb.append('=');
sb.append(this.additionalProperties == null ? "<null>" : this.additionalProperties);
sb.append(',');
if (sb.charAt(sb.length() - 1) == ',') {
sb.setCharAt(sb.length() - 1, ']');
} else {
sb.append(']');
}
return sb.toString();
}
public int hashCode() {
int result = 1;
result = result * 31 + (this.ua == null ? 0 : this.ua.hashCode());
result = result * 31 + (this.devicetype == null ? 0 : this.devicetype.hashCode());
result = result * 31 + (this.ip == null ? 0 : this.ip.hashCode());
result = result * 31 + (this.dnt == null ? 0 : this.dnt.hashCode());
return result;
}
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (!(other instanceof Device)) {
return false;
} else {
Device rhs = (Device)other;
return (Objects.equals(this.ua, rhs.ua))
&& (Objects.equals(this.devicetype, rhs.devicetype) || this.devicetype != null
&& this.devicetype.equals(rhs.devicetype))
&& (Objects.equals(this.ip, rhs.ip))
&& (Objects.equals(this.dnt, rhs.dnt)) ;
}
}
}
下面是解析 json -
的 java 代码
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class DeviceJsonParserDemo {
public static void main(String[] args) throws IOException {
ObjectMapper jsonMapperBidRequest = new ObjectMapper();
String dev = Files.readString(Paths.get("src/main/resources/device.json"));
Device device = jsonMapperBidRequest.readValue(dev, Device.class);
System.out.println(device);
}
}
当你运行上面的代码你会得到下面的输出-
Device@5876a9af[ua=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36,dnt=<null>,ip=<null>,devicetype=<null>,additionalProperties={started=now, devtime=now}]
正如您在上面的输出中注意到的,不在 Device class 中的字段在 additionalProperties 字段中。
现在我想把上面的逻辑迁移到typelevel circe
我已解码
import io.circe.{Decoder, HCursor}
case class Device (ua: String, dnt: Option[Int], ip: Option[String], devicetype: Option[Int], addlProperties: Map[String, Any] = Map.empty)
object Device {
implicit val decodeFoo: Decoder[Device] = new Decoder[Device] {
final def apply(c: HCursor): Decoder.Result[Device] =
for {
ua <- c.downField("ua").as[String]
dnt <- c.downField("dnt").as[Option[Int]]
ip <- c.downField("ip").as[Option[String]]
devicetype <- c.downField("devicetype").as[Option[Int]]
} yield new Device(ua, dnt, ip, devicetype)
}
}
java解析逻辑为
import scala.io.Source
import io.circe.parser._
object DeviceJsonCirceDecodeDemo extends App {
val devString = Source.fromFile("src/main/resources/device.json").mkString
val device = decode[Device](devString)
println(device)
}
当我 运行 上述代码时,我得到以下输出 -
Right(Device(Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36,None,None,None,Map()))
如您所见,addlProperties
地图是空的,因为它没有解码器。
一个相对简单但难以维护的解决方案是将整个对象解码为 Map 并删除已知键。
您的解码器将变为:
implicit val decodeFoo: Decoder[Device] = Decoder.instance(c =>
for {
ua <- c.get[String]("ua")
dnt <- c.get[Option[Int]]("dnt")
ip <- c.get[Option[String]]("ip")
devicetype <- c.get[Option[Int]]("devicetype")
additional <- c.as[Map[String, Json]].map(_ - "ua" - "dnt" - "ip" - "devicetype")
} yield new Device(ua, dnt, ip, devicetype, additional)
)
我已将 new Decoder
替换为 Decoder.instance
,将 c.downField(...).as[...]
替换为 c.get[...](...)
。
这还假设 addlProperties
是 Map[String, Json]
,您可能希望为一组特定类型定义解码器。
我正在重写一些 java 代码,这些代码使用 jackson json 解析为 scala circe。
javaDevice
class是这个-
package forjava;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({"ua", "dnt", "ip", "devicetype"})
public class Device implements Serializable {
@JsonProperty("ua")
private String ua;
@JsonProperty("dnt")
private Integer dnt;
@JsonProperty("ip")
private String ip;
@JsonProperty("devicetype")
private Integer devicetype;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap();
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
private static final long serialVersionUID = -4938649324295079141L;
public Device() {
}
public Device(String ua, Integer dnt, Integer lmt, String ip, String ipv6, Integer devicetype, String make) {
this.ua = ua;
this.dnt = dnt;
this.ip = ip;
this.devicetype = devicetype;
}
@JsonProperty("ua")
public String getUa() {
return this.ua;
}
@JsonProperty("ua")
public void setUa(String ua) {
this.ua = ua;
}
@JsonProperty("dnt")
public Integer getDnt() {
return this.dnt;
}
@JsonProperty("dnt")
public void setDnt(Integer dnt) {
this.dnt = dnt;
}
@JsonProperty("ip")
public String getIp() {
return this.ip;
}
@JsonProperty("ip")
public void setIp(String ip) {
this.ip = ip;
}
@JsonProperty("devicetype")
public Integer getDevicetype() {
return this.devicetype;
}
@JsonProperty("devicetype")
public void setDevicetype(Integer devicetype) {
this.devicetype = devicetype;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(Device.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
sb.append("ua");
sb.append('=');
sb.append(this.ua == null ? "<null>" : this.ua);
sb.append(',');
sb.append("dnt");
sb.append('=');
sb.append(this.dnt == null ? "<null>" : this.dnt);
sb.append(',');
sb.append("ip");
sb.append('=');
sb.append(this.ip == null ? "<null>" : this.ip);
sb.append(',');
sb.append("devicetype");
sb.append('=');
sb.append(this.devicetype == null ? "<null>" : this.devicetype);
sb.append(',');
sb.append("additionalProperties");
sb.append('=');
sb.append(this.additionalProperties == null ? "<null>" : this.additionalProperties);
sb.append(',');
if (sb.charAt(sb.length() - 1) == ',') {
sb.setCharAt(sb.length() - 1, ']');
} else {
sb.append(']');
}
return sb.toString();
}
public int hashCode() {
int result = 1;
result = result * 31 + (this.ua == null ? 0 : this.ua.hashCode());
result = result * 31 + (this.devicetype == null ? 0 : this.devicetype.hashCode());
result = result * 31 + (this.ip == null ? 0 : this.ip.hashCode());
result = result * 31 + (this.dnt == null ? 0 : this.dnt.hashCode());
return result;
}
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (!(other instanceof Device)) {
return false;
} else {
Device rhs = (Device)other;
return (Objects.equals(this.ua, rhs.ua))
&& (Objects.equals(this.devicetype, rhs.devicetype) || this.devicetype != null
&& this.devicetype.equals(rhs.devicetype))
&& (Objects.equals(this.ip, rhs.ip))
&& (Objects.equals(this.dnt, rhs.dnt)) ;
}
}
}
下面是解析 json -
的 java 代码import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class DeviceJsonParserDemo {
public static void main(String[] args) throws IOException {
ObjectMapper jsonMapperBidRequest = new ObjectMapper();
String dev = Files.readString(Paths.get("src/main/resources/device.json"));
Device device = jsonMapperBidRequest.readValue(dev, Device.class);
System.out.println(device);
}
}
当你运行上面的代码你会得到下面的输出-
Device@5876a9af[ua=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36,dnt=<null>,ip=<null>,devicetype=<null>,additionalProperties={started=now, devtime=now}]
正如您在上面的输出中注意到的,不在 Device class 中的字段在 additionalProperties 字段中。
现在我想把上面的逻辑迁移到typelevel circe
我已解码
import io.circe.{Decoder, HCursor}
case class Device (ua: String, dnt: Option[Int], ip: Option[String], devicetype: Option[Int], addlProperties: Map[String, Any] = Map.empty)
object Device {
implicit val decodeFoo: Decoder[Device] = new Decoder[Device] {
final def apply(c: HCursor): Decoder.Result[Device] =
for {
ua <- c.downField("ua").as[String]
dnt <- c.downField("dnt").as[Option[Int]]
ip <- c.downField("ip").as[Option[String]]
devicetype <- c.downField("devicetype").as[Option[Int]]
} yield new Device(ua, dnt, ip, devicetype)
}
}
java解析逻辑为
import scala.io.Source
import io.circe.parser._
object DeviceJsonCirceDecodeDemo extends App {
val devString = Source.fromFile("src/main/resources/device.json").mkString
val device = decode[Device](devString)
println(device)
}
当我 运行 上述代码时,我得到以下输出 -
Right(Device(Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36,None,None,None,Map()))
如您所见,addlProperties
地图是空的,因为它没有解码器。
一个相对简单但难以维护的解决方案是将整个对象解码为 Map 并删除已知键。
您的解码器将变为:
implicit val decodeFoo: Decoder[Device] = Decoder.instance(c =>
for {
ua <- c.get[String]("ua")
dnt <- c.get[Option[Int]]("dnt")
ip <- c.get[Option[String]]("ip")
devicetype <- c.get[Option[Int]]("devicetype")
additional <- c.as[Map[String, Json]].map(_ - "ua" - "dnt" - "ip" - "devicetype")
} yield new Device(ua, dnt, ip, devicetype, additional)
)
我已将 new Decoder
替换为 Decoder.instance
,将 c.downField(...).as[...]
替换为 c.get[...](...)
。
这还假设 addlProperties
是 Map[String, Json]
,您可能希望为一组特定类型定义解码器。