在开发过程中,我们经常会进行JSONObject对像和Java实体类对像的相互转换。使用场景无非下面三种:
Person转换为JSONObject | ||
Person属性:值 | ----> | JSONObject属性:值 |
userName:zs | ----> | userName:zs |
userAge:18 | ----> | userAge:18 |
idNumber:1001 | ----> | idNumber:1001 |
JSONObject转换为Person(属性一致) | ||
JSONObject属性:值 | ----> | Person属性:值 |
userName:zs | ----> | userName:zs |
userAge:18 | ----> | userAge:18 |
idNumber:1001 | ----> | idNumber:1001 |
JSONObject转换为Person(属性不一致) | ||
JSONObject属性:值 | ----> | Person属性:值 |
name:zs | ----> | userName:null |
age:18 | ----> | userAge:null |
idNumber:1001 | ----> | idNumber:1001 |
对于前两种转换,我们不用额外考虑什么,直接转换就行了。但是对于第三种情况,即JSONObject对像里的属性名称和Person对像里的属性名称不一致,那么就会导致转换后的Person对像里userName和userAge的属性为null,这显然不是我们想要的结果。
这种情况在实际开发中还是经常存在的,特别是在多系统、多数据源的情况下,通常我们约定的都是json格式的字符串,但是对json字符串里的字段名称等内容,却经常不可控。
比方说,下划线命名(这种情况下,实际也可以正确给person对像赋值):
{
"user_age":"18",
"user_name":"zhangsan",
"id_number":"1001"
}
比方说,奇怪的编码:
{
"p001":"18",
"p002":"zhangsan",
"p003":"1001"
}
这种情况下,再智能的工具也无法正确解析了,只会看到person的属性全部都是null。
实际测试如下:
public static void main(String[] args) {
String strA = "{\n" +
" \"user_age\":\"18\",\n" +
" \"user_name\":\"zhangsan\",\n" +
" \"id_number\":\"1001\"\n" +
"}";
JSONObject jsonObjectA = JSONObject.parseObject(strA);
Person personA = JSON.parseObject(jsonObjectA.toJSONString(), Person.class);
System.out.println("personA: " + personA);
String strB = "{\n" +
" \"P001\":\"18\",\n" +
" \"P002\":\"zhangsan\",\n" +
" \"P003\":\"1001\"\n" +
"}";
JSONObject jsonObjectB = JSONObject.parseObject(strB);
Person personB = JSON.parseObject(jsonObjectB.toJSONString(), Person.class);
System.out.println("personB: " + personB);
}
执行结果:
那么,该如何解决呢?
这个时候,注解@JSONField就派上用场了。@JSONField注解可以改变序列化和反序列化字段的名称。
这个注解的源代码如下:
/*
* Copyright 1999-2101 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.fastjson.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
* @author wenshao[szujobs@hotmail.com]
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
/**
* config encode/decode ordinal
* @since 1.1.42
* @return
*/
int ordinal() default 0;
String name() default "";
String format() default "";
boolean serialize() default true;
boolean deserialize() default true;
SerializerFeature[] serialzeFeatures() default {};
Feature[] parseFeatures() default {};
String label() default "";
/**
* @since 1.2.12
*/
boolean jsonDirect() default false;
/**
* Serializer class to use for serializing associated value.
*
* @since 1.2.16
*/
Class<?> serializeUsing() default Void.class;
/**
* Deserializer class to use for deserializing associated value.
*
* @since 1.2.16
*/
Class<?> deserializeUsing() default Void.class;
/**
* @since 1.2.21
* @return the alternative names of the field when it is deserialized
*/
String[] alternateNames() default {};
}
可以看到,它可以用在方法上,类的成员变量上,方法中的参数上。
用在字段上,如下:
package ztt.JSONFieldtest;
import com.alibaba.fastjson.annotation.JSONField;
/**
* @date 20200728
*/
public class Person {
@JSONField(name = "P001")
private String userName;
@JSONField(name = "P002")
private String userAge;
private String idNumber;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAge() {
return userAge;
}
public void setUserAge(String userAge) {
this.userAge = userAge;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
@Override
public String toString() {
return "Person{" +
"userName='" + userName + '\'' +
", userAge='" + userAge + '\'' +
", idNumber='" + idNumber + '\'' +
'}';
}
}
用在方法上,如下列所示:
@JSONField(name = "P001")
public String getUserName() {
return userName;
}
@JSONField(name = "P001")
public void setUserName(String userName) {
this.userName = userName;
}
这个时候,我们再做对像之间的转换,如下图所示:
public static void main(String[] args) {
String strB = "{\n" +
" \"P001\":\"18\",\n" +
" \"P002\":\"zhangsan\",\n" +
" \"idNumber\":\"1001\"\n" +
"}";
JSONObject jsonObjectB = JSONObject.parseObject(strB);
Person personB = JSON.parseObject(jsonObjectB.toJSONString(), Person.class);
System.out.println("personB: " + personB);
}
执行结果:
可以看到,json对像字符串属性名称和person对像属性不一致,也能正常转化了。