Java Json Binding JSON-B使用示例

JSON-B是用于将Java对象与JSON消息相互转换的标准绑定层。它定义了一种默认的映射算法,用于将现有的Java类转换为JSON,同时使开发人员可以通过使用Java注释自定义映射过程。

安装

座标

Maven依赖

<dependencies>

    <!-- JSON-P API -->

    <dependency>

        <groupId>javax.json</groupId>

        <artifactId>javax.json-api</artifactId>

        <version>1.1</version>

    </dependency>

 

    <!-- JSON-P RI -->

    <dependency>

        <groupId>org.glassfish</groupId>

        <artifactId>javax.json</artifactId>

        <version>1.1</version>

        <scope>runtime</scope>

    </dependency>

 

    <!-- JSON-B API -->

    <dependency>

        <groupId>javax.json.bind</groupId>

        <artifactId>javax.json.bind-api</artifactId>

        <version>1.0.0-RC2</version>

    </dependency>

 

    <!-- Yasson (JSON-B RI) -->

    <dependency>

        <groupId>org.eclipse</groupId>

        <artifactId>yasson</artifactId>

        <version>1.0.0-RC1</version>

        <scope>runtime</scope>

    </dependency>

</dependencies>

JSON绑定API

默认映射

默认映射是JSON-B引擎默认使用的一组规则,没有提供任何自定义注释和自定义配置。

JSON-B的主要入口点是Jsonb类。它提供了一组重载的toJson和fromJson方法,以将Java对象序列化为JSON文档并反序列化它们。Jsonb实例是线程安全的,可以重用。推荐的方法是每个配置类型具有一个实例。

默认的Jsonb引擎可以这样创建:

Jsonb jsonb = JsonbBuilder.create();

映射对象

下面的示例演示简单POJO的序列化和反序列化。

public class Dog {

    public String name;

    public int age;

    public boolean bitable;

}

 

// Create a dog instance

Dog dog = new Dog();

dog.name = "Falco";

dog.age = 4;

dog.bitable = false;

 

// Create Jsonb and serialize

Jsonb jsonb = JsonbBuilder.create();

String result = jsonb.toJson(dog);

 

// Deserialize back

dog = jsonb.fromJson("{name:\"Falco\",age:4,bitable:false}", Dog.class);

映射集合

JSON-B支持集合和通用集合处理。为了进行适当的反序列化,需要在反序列化期间将所得对象的运行时类型传递给JSON-B。可以按照以下所示的方法来完成。

// List of dogs

List dogs = new ArrayList();

dogs.add(falco);

dogs.add(cassidy);

 

// Create Jsonb and serialize

Jsonb jsonb = JsonbBuilder.create();

String result = jsonb.toJson(dogs);

 

// Deserialize back

dogs = jsonb.fromJson(result, ArrayList.getClass());

映射通用集合

JSON-B支持集合和通用集合处理。为了进行适当的反序列化,需要在反序列化期间将所得对象的运行时类型传递给JSON-B。可以按照以下所示的方法来完成。

// List of dogs

List<Dog> dogs = new ArrayList<>();

dogs.add(falco);

dogs.add(cassidy);

 

// Create Jsonb and serialize

Jsonb jsonb = JsonbBuilder.create();

String result = jsonb.toJson(dogs);

 

// Deserialize back

dogs = jsonb.fromJson(result, new ArrayList<Dog>(){}.getClass().getGenericSuperclass());

定制映射

您可以通过许多不同的方式自定义映射。您可以将JSON-B批注用于编译时定制,而可以将JsonbConfig类用于运行时定制。

以下示例显示了如何使用自定义配置创建JSON-B引擎:

// Create custom configuration

JsonbConfig config = new JsonbConfig();

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

格式化输出

// Create custom configuration with formatted output

JsonbConfig config = new JsonbConfig()

    .withFormatting(true);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

// Use it!

String result = jsonb.toJson(pojo);

更改属性名称

默认情况下,JSON属性名称与Java属性名称相同。一个常见的用例是使用不同的名称序列化属性。这可以通过在字段上使用@JsonbProperty注释来实现,也可以使用JsonbNamingStrategy全局地实现。

@JsonbProperty批注

@JsonbProperty用于更改一个特定属性的名称。可以放置

  • 现场,在这种情况下会影响序列化和反序列化
  • 在吸气剂上,在这种情况下,它将仅影响序列化
  • 在setter上,在这种情况下,它将仅影响反序列化

在下面的示例属性中,属性名称将被序列化为“ person-name”。

public class Person {

    @JsonbProperty("person-name")

    private String name;

 

    private String profession;

}

生成的JSON文档将如下所示:

{

    "person-name": "Jason Bourne",

    "profession": "Super Agent"

}

如果将@JsonbProperty批注放在getter上,将生成相同的JSON文档,如下所示:

public class Person {

    private String name;

    private String profession;

 

    @JsonbProperty("person-name")

    public String getName() {

        return name;

    }

}

此示例演示了将属性写入一个JSON属性并从另一个属性读取的能力。属性'name'被序列化为'name-to-write'属性,并在反序列化期间从'name-to-read'属性读取。

public class Person {

    private String name;

    private String profession;

 

    @JsonbProperty("name-to-write")

    public String getName() {

        return name;

    }

 

    @JsonbProperty("name-to-read")

    public void setName(String name) {

        this.name = name;

    }

}

命名策略

命名策略用于更改构造属性名称的默认方式。

支持的命名策略是:

  • 身份(myMixedCaseProperty)
  • LOWER_CASE_WITH_DASHES(我的混合案例属性)
  • LOWER_CASE_WITH_UNDERSCORES(my_mixed_case_property)
  • UPPER_CAMEL_CASE(MyMixedCaseProperty)
  • UPPER_CAMEL_CASE_WITH_SPACES(我的混合大小写财产)
  • CASE_INSENSITIVE(mYmIxEdCaSePrOpErTy)
  • 或您的JsonbNamingStrategy接口的自定义实现

IDENTITY策略是默认策略。

可以与JsonbConfig类的withPropertyNamingStrategy方法一起使用:

// Custom configuration

JsonbConfig config = new JsonbConfig()

    .withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_DASHES);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

...

属性顺序

为了自定义序列化属性的顺序,JSON Binding提供了PropertyOrderStrategy类。

支持的策略是:

  • 词汇(AZ)
  • ANY(顺序未定义,在大多数情况下,顺序将在类中显示属性)
  • 倒车(ZA)

默认订购策略为LEXICOGRAPHICAL。可以使用JsonbConfig类的withPropertyOrderStrategyy方法全局应用订购策略:

// Custom configuration

JsonbConfig config = new JsonbConfig()

    .withPropertyOrderStrategy(PropertyOrderStrategy.ANY);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

...

或在类上使用@JsonbPropertyOrder批注:

@JsonbPropertyOrder(PropertyOrderStrategy.ANY)

public class Person {

    private String name;

    private String profession;

}

忽略属性

使用@JsonbTransient注释注释的类属性将被JSON绑定引擎忽略。行为因@JsonbTransient批注的放置位置而异。

  • 现场:在序列化和反序列化期间,将忽略属性。
  • 在getter上:仅在序列化期间忽略属性。
  • 在setter上:仅在反序列化期间忽略属性。

此类的序列化

@JsonbPropertyOrder(PropertyOrderStrategy.ANY)

public class Person {

    @JsonbTransient

    private String name;

 

    private String profession;

}

将产生以下JSON文档:

{

    "profession": "Super Agent"

}

如果将@JsonbTransient批注这样放置在getter上:

public class Person {

    private String name;

    private String profession;

 

    @JsonbTransient

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

}

'name'属性不会被序列化,但是会被反序列化。

空处理

默认情况下,JSON-B不会序列化具有空值的字段。这可能是不希望的行为。有三种不同的方法可以更改默认的空值处理。

  • 在类或包级别使用@JsonbNillable批注

@JsonbNillable

public class Person {

    private String name;

    private String profession;

}

  • 在使用@JsonbProperty批注和nillable = true参数的单个属性上

public class Person {

    @JsonbProperty(nillable=true)

    private String name;

 

    private String profession;

}

  • 全局使用JsonbConfig类的withNullValues方法

// Create custom configuration

JsonbConfig nillableConfig = new JsonbConfig()

    .withNullValues(true);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(nillableConfig);

 

...

自定义实例

默认情况下,反序列化需要使用公共默认的无参数构造函数。在许多情况下,此要求过于严格。JSON-B提供@JsonbCreator批注,可用于使用参数或用于创建类实例的静态工厂方法对自定义构造函数进行批注。

下面的示例显示了如何在自定义构造函数上使用@JsonbCreator批注。必须使用构造函数参数上的@JsonbProperty批注来正确替换参数。在这种情况下,会将JSON属性“名称”的值传递给构造函数。

public class Person {

    private String name;

    private String profession;

 

    @JsonbCreator

    public Person(@JsonbProperty("name") String name) {

        this.name = name;

    }

}

日期/数字格式

默认情况下,JSON-B使用ISO格式对日期和数字字段进行序列化和反序列化。有时需要覆盖这些设置。可以在字段上使用@JsonbDateFormat和@JsonbNumberFormat批注来完成:

public class Person {

    public String name;

 

    @JsonbDateFormat("dd.MM.yyyy")

    private Date birthDate;

 

    @JsonbNumberFormat(“#0.00")

    public BigDecimal salary;

}

或全局使用JsonbConfig类的withDateFormat方法:

// Create custom configuration

JsonbConfig config = new JsonbConfig()

    .withDateFormat("dd.MM.yyyy", null);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

...

二进制编码

JSON-B支持二进制数据的映射。默认情况下,它使用BYTE编码,但是可以使用BinaryDataStrategy类轻松对其进行自定义,该类提供对最常见的二进制数据编码的支持:

  • 字节
  • BASE_64
  • BASE_64_URL

以下示例显示了使用BASE_64_URL编码的Jsonb引擎的创建:

// Create custom configuration

JsonbConfig config = new JsonbConfig()

    .withBinaryDataStrategy(BinaryDataStrategy.BASE_64);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

...

转接器

在某些情况下,可能很难以所需方式对类进行序列化/反序列化。有时无法在源代码上放置自定义注释,因为您无权访问它,或者自定义注释不能解决问题。在这种情况下,可以尝试使用适配器。

Adapter是一个实现javax.json.bind.adapter.JsonbAdapter接口的类。它具有一个自定义代码,可将“不可映射”类型(原始)转换为所需方式序列化/反序列化的另一种(“自适应”)。嘲讽JAXB中的类型适配器如何工作。

让我们看一下示例。假设您有一个包含所有客户详细信息的Customer对象。在一种情况下,您需要序列化整个对象,在另一种情况下,您仅需要提供其ID和名称。解决方案可能是将其序列化为第一种情况,并为JsonObject创建一个适配器,该适配器仅包含第二种情况所需的数据。

public class Customer {

    private int id;

    private String name;

    private String organization;

    private String position;

 

    ...

}

 

public class CustomerAdapter implements JsonbAdapter<Customer, JsonObject> {

    @Override

    public JsonObject adaptToJson(Customer c) throws Exception {

        return Json.createObjectBuilder()

            .add("id", c.getId())

            .add("name", c.getName())

            .build();

    }

 

    @Override

    public Customer adaptFromJson(JsonObject adapted) throws Exception {

        Customer c = new Customer();

        c.setId(adapted.getInt("id"));

        c.setName(adapted.getString("name"));

        return c;

    }

}

第一种情况:

// Create Jsonb with default configuration

Jsonb jsonb = JsonbBuilder.create();

 

// Create customer

Customer c = new Customer();

 

// Initialization code is skipped

 

// Serialize

jsonb.toJson(customer);

结果:

{

    "id": 1,

    "name": "Json Bourne",

    "organization": "Super Agents",

    "position": "Super Agent"

}

第二种情况:

// Create custom configuration

JsonbConfig config = new JsonbConfig()

    .withAdapters(new CustomerAdapter());

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

// Create customer

Customer c = new Customer();

 

// Initialization code is skipped

 

// Serialize

jsonb.toJson(customer);

结果:

{

    "id": 1,

    "name": "Json Bourne"

}

序列化器/反序列化器

有时,适配器机制还不够,因此需要对JSONP解析器/生成器的低级别访问。

从规格:

Serializer是一个实现javax.json.bind.serializers.JsonbSerializer接口的类。它用于序列化其在(原始)上注册的类型。在对原始类型进行序列化时,JSONB调用JsonbSerializer :: serialize方法。此方法必须包含一个自定义代码,才能使用提供的JsonpGenerator序列化Original类型。

Deserializer是实现javax.json.bind.serializers.JsonbDeserializer接口的类。它用于反序列化其在(原始)上注册的类型。在对原始类型进行反序列化时,JSONB调用JsonbDeserializer :: deserialize方法。此方法必须包含一个自定义代码,以使用提供的JsonpParser反序列化Original类型。

让我们看一下示例。想象一下,我们想序列化和反序列化宠物载体列表。由抽象类Animal定义的宠物。它可以是其任何子类。我们想适当地序列化和反序列化它。为此,我们需要在JSON文档中保留类型信息,并在反序列化时使用它。可以使用自定义的串行器/解串器对来完成。

模型:

public abstract class Animal {

    private String name;

    private int age;

    private Boolean furry;

 

    ...

}

 

public class Cat extends Animal {

    private Boolean cuddly;

 

    ...

}

 

public class Dog extends Animal {

    private Boolean barking;

 

    ...

}

 

public class Carrier<P extends Pet> {

    public enum TYPE {

        BAG, CRATE, TROLLEY

    }

 

    private TYPE carrierType;

    private P carriedPet;

 

    @JsonbCreator

    public Carrier(TYPE carrierType, A carriedPet) {

        this.carrierType = carrierType;

        this.carriedPet = carriedPet;

    }

 

    ...

}

序列化器/解串器:

public class AnimalSerializer implements JsonbSerializer<Animal> {

    public void serialize(Animal animal, JsonGenerator jsonGenerator, SerializationContext serializationContext) {

        if (animal != null) {

            serializationContext.serialize(animal.getClass().getName(), animal, jsonGenerator);

        } else {

            serializationContext.serialize(null, jsonGenerator);

        }

    }

}

 

public class AnimalDeserializer implements JsonbDeserializer<Animal> {

    public Animal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext, Type type) {

        Animal animal = null;

        while (jsonParser.hasNext()) {

            JsonParser.Event event = jsonParser.next();

            if (event == JsonParser.Event.KEY_NAME) {

                String className = jsonParser.getString();

                jsonParser.next();

                try {

                    animal = deserializationContext.deserialize(Class.forName(className).asSubclass(Animal.class), jsonParser);

                } catch (ClassNotFoundException e) {

                    e.printStackTrace();

                }

            }

        }

        return animal;

    }

}

用法:

// Create a list of carrier objects

List<Carrier<Pet>> carriers = new ArrayList<>();

carriers.add(new Carrier<>(Carrier.TYPE.BAG, new Cat("Harris", 10, true, true)));

carriers.add(new Carrier<>(Carrier.TYPE.CRATE, new Dog("Falco", 4, false, false)));

Type carrierListType = new ArrayList<Carrier<Pet>>() {}.getClass().getGenericSuperclass();

 

JsonbConfig config = new JsonbConfig()

        .withFormatting(true)

        .withSerializers(new PetSerializer())

        .withDeserializers(new PetDeserializer());

 

Jsonb jsonb = JsonbBuilder.create(config);

 

String json = jsonb.toJson(carriers, carrierListType);

System.out.println(json);

 

List<Carrier<Pet>> list = jsonb.fromJson(json, carrierListType);

System.out.println(list.get(0).getCarriedPet().getClass().getName());

严格的I-JSON支持

I-JSON(“ Internet JSON”)是JSON的受限配置文件。JSON-B默认情况下完全支持I-JSON,但有以下三个例外:

  • JSON绑定不限制既不是对象也不是数组的顶级JSON文本的序列化。该限制应发生在应用程序级别。
  • JSON绑定不会使用base64url编码序列化二进制数据。
  • JSON绑定不会对日期/时间/持续时间实施其他限制。

可以如下所示打开完全支持模式:

// Create custom configuration

JsonbConfig config = new JsonbConfig()

    .withStrictIJSON(true);

 

// Create Jsonb with custom configuration

Jsonb jsonb = JsonbBuilder.create(config);

 

...

更多的信息

最后更新2017-06-09 17:57:04 CEST

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值