Java技术小结与探索

在想要攀登到科学顶峰之前,务必把科学的初步知识研究透彻。还没有充分领会前面的东西时,就决不要动手搞往后的事情。

Spring

Bean与Component

@Component(@Controller @Service @Respository):Class

  • 表明该类会作为组件类,告知Spring容器为该类创建bean(通过类路径扫描自动装配到Spring容器中)。
  • 通过组件扫描,Spring将扫描整个类路径,并将所有@Component注释类添加到Spring Context。Component会把整个类当成bean注册到Spring容器中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class User {
private String name;
private Integer id;

public User() {
}

public User(String name, Integer id) {
this.name = name;
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}

Dao层

1
2
3
4
5
public interface UserDao {
int addUser(User user);
int deleteUserById(int id);
User selectUserByID(int id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*通常由MyBatis完成*/
@Repository
public class UserDaoImpl implements UserDao {
@Override
public int addUser(User user) {
System.out.println("->UserDaoImpl:addUser");
return 1;
}

@Override
public int deleteUserById(int id) {
System.out.println("->UserDaoImpl:deleteUser");
return 1;
}

@Override
public User selectUserByID(int id) {
System.out.println("->UserDaoImpl:selectUserByID");
return new User("tester",1);
}

}

Service层

1
2
3
4
5
public interface UserService {
int addUser(User user);
int deleteUserById(int id);
User selectUserByID(int id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


@Service /*去掉Service自动装配UserServiceImpl2*/
@Primary
public class UserServiceImpl1 implements UserService {
@Autowired
UserDao userDao;
@Override
public int addUser(User user) {

return userDao.addUser(user);
}

@Override
public int deleteUserById(int id) {
return userDao.deleteUserById(id);
}

@Override
public User selectUserByID(int id) {
System.out.print("===UserServiceImpl1:");
return userDao.selectUserByID(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service
public class UserServiceImpl2 implements UserService {
@Autowired
UserDao userDao;
@Override
public int addUser(User user) {
return userDao.addUser(user);
}

@Override
public int deleteUserById(int id) {
return userDao.deleteUserById(id);
}

@Override
public User selectUserByID(int id) {
System.out.print("===UserServiceImpl2:");
return userDao.selectUserByID(id);
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
@SpringBootTest
class MyApplicationTests {
/*Could not autowire. There is more than one bean of 'UserService' type.Beans:userServiceImpl1 (UserServiceImpl1.java)userServiceImpl2 (UserServiceImpl2.java)*/
@Autowired
UserService userService;
@Test
public void test(){
userService.selectUserByID(1);
}

}

1
2
3
4
@Service
@Qualifier("userServiceImpl1")
public class UserServiceImpl1 implements UserService {
}
1
2
3
4
@Service
@Qualifier("userServiceImpl2")
public class UserServiceImpl2 implements UserService {
}
1
2
3
@Autowired
@Qualifier("userServiceImpl1")
UserService userService;

@Autowired自动装配:根据UserDao的类型寻找对应的bean,此处即为UserDao注册在Spring容器中的两个对应的实现类UserServiceImpl1和UserServiceImpl2(虽然定义属性是接口类型,但最终装配时是对应的实现类)。当该接口具有多个实现类,需要在@Autowired自动装配时使用@Primary(在实现类上使用,即优先选择)或者@Qualifier进行指定一个实现类进行注入。



@Bean:Method

  • 表明该方法将会返回一个对象,该对象会注册为Spring应用上下文的bean。通常该方法定义产生bean实例的逻辑。
  • 更加灵活,可以独立加在方法上(Bean的声明与类定义分离),按需注册到Spring容器,当需要用到第三方类库里面某个方法,可以用@Bean把这个方法注册到Spring容器。
  • 需要在配置类中使用,即类上需用@Configuration注解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class MyBean {
private String myBeanName;
@Value("1")
private Integer myBeanId;

public String getMyBeanName() {
return myBeanName;
}

public void setMyBeanName(String myBeanName) {
this.myBeanName = myBeanName;
}

public Integer getMyBeanId() {
return myBeanId;
}

public void setMyBeanId(Integer myBeanId) {
this.myBeanId = myBeanId;
}

@Override
public String toString() {
return "MyBean{" +
"myBeanName='" + myBeanName + '\'' +
", myBeanId=" + myBeanId +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
@Configuration
public class AppConfig {
/*bean名称默认方法名*/
@Bean
public MyBean myBean(){
MyBean myBean = new MyBean();
myBean.setMyBeanName("MyFirstBean");
return myBean;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@SpringBootTest
class MyBeanApplicationTests {

@Autowired
MyBean myBean2;

@Test
public void testMyBean(){
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
/*1.@AutoWired可通过byName byType constructor和autodetect方式进行自动装配,所以修改方法名仍然可以自动装配,此处无法根据错误的方法名获取bean
2.方法名通常是返回类名首字母小写*/
Object myBean1 = context.getBean("myBean");
System.out.println(myBean1);
MyBean myFirstBean = (MyBean)myBean1;
System.out.println(myFirstBean.getMyBeanName());
}
@Test
public void testMyBean2() {
System.out.println(myBean2.toString());
}

}

二者都可以通过@Autowired装配


@Component and Further Stereotype Annotations

The @Repository annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions, as described in Exception Translation.

Spring provides further stereotype annotations: @Component, @Service, and @Controller. @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases (in the persistence, service, and presentation layers, respectively). Therefore, you can annotate your component classes with @Component, but, by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. @Repository, @Service, and @Controller can also carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice. Similarly, as stated earlier, @Repository is already supported as a marker for automatic exception translation in your persistence layer.

Annotation Meaning Scope
@Component generic stereotype for any Spring-managed component 组件类
@Repository stereotype for persistence layer 数据库操作、数据传至Service(@Service)层
@Service stereotype for service layer 业务逻辑、数据处理、调用持久层(Persistence layer/Data Access Layer @Repository)方法等
@Controller stereotype for presentation layer (spring-mvc) 处理请求(调度、转发、调用Service(@Service层)方法等)


Java JSON

Jackson

Jackson

Jackson是当前用的比较广泛的,用来序列化和反序列化 json 的Java开源框架,是Spring MVC 默认json 解析器。

特点:

  • 依赖关系较少

  • 解析大json文件速度较快

  • 占用内存比较低,性能比较好

  • 易于使用


Fastjson

FastJSON

fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。

特点:

  • 速度快

  • 国内使用广泛

  • 测试完备

  • 使用简单


Gson

Gson

Gson使用指南

Gson(Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。

Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。

Spring与Gson

如果使用Gson作为默认库,需要从classpath中删除Jackson

  • 使用Maven
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- Exclude the default Jackson dependency -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
  • Exclude property
1
2
3
4
5
6
7
@SpringBootApplication(exclude = {JacksonAutoConfiguration.class})
public class GsonSpringBootApplication {

public static void main(String[] args) {
SpringApplication.run(GsonSpringBootApplication.class, args);
}
}

使用HttpMessageConverters自定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*自定义JSON转换日期格式*/
@Configuration
public class ApplicationConfig extends WebMvcConfigurerAdapter {

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(customGsonHttpMessageConverter());
super.configureMessageConverters(converters);
}

private GsonHttpMessageConverter customGsonHttpMessageConverter() {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'")
.create();

GsonHttpMessageConverter gsonMessageConverter = new GsonHttpMessageConverter();
gsonMessageConverter.setGson(gson);

return gsonMessageConverter;
}
}

1.Gson基本用法

Gson提供fromJson()toJson() 两个方法用于反序列化和序列化。

  • Gson.toJson(Object)
  • Gson.fromJson(String,Class)
  • Gson.fromJson(String,Type)
  • 反序列化

    • 基本类型
    1
    2
    3
    4
    5
    Gson gson = new Gson();
    int i = gson.fromJson("100", int.class); /*100*/
    double aDouble = gson.fromJson("99.99", double.class); /*99.99*/
    boolean aBoolean = gson.fromJson("true", boolean.class); /*true*/
    String aString = gson.fromJson("String", String.class); /*String*/
    • 简单实体类
    1
    2
    3
    4
    5
    6
    7
    8
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Product {
    private String id;
    private String name;
    private Double price;
    }
    1
    2
    3
    Gson gson = new Gson();
    Product sugar_box = new Product("20210103", "Sugar Box", 15.69);
    String jsonString = gson.toJson(sugar_box); /*{"id":"20210103","name":"Sugar Box","price":15.69}*/
  • 序列化

    • 基本类型
    1
    2
    3
    4
    Gson gson = new Gson();
    String jsonNumber = gson.toJson(100); /*100*/
    String jsonBoolean = gson.toJson(false); /*false*/
    String jsonString = gson.toJson("String"); /*String*/
    • 简单实体类
    1
    2
    3
    Gson gson = new Gson();
    String jsonString1 = "{\"id\":\"20210103\",\"name\":\"Sugar Box\",\"price\":15.69}";
    Product sugar_box = gson.fromJson(jsonString1,Product.class); /*Product(id=20210103, name=Sugar Box, price=15.69)*/

2.@SerializedName

@SerializedName:属性重命名,可以将json中的属性名转换为自定义的属性名(原属性名失效)

  • value:json属性名
  • alternate:(备选属性名)接收一个String数组alternate数组中出现任意一个属性名都可以转换为自定义的属性,如果出现多个则以最后一个为准
1
2
@SerializedName("box_price")
private Double price;
1
2
3
4
5
6
7
8
9
Gson gson = new Gson();
String jsonStr1 = "{\"id\":\"20090804\",\"name\":\"Wooden Box\",\"box_price\":16.69}";
String jsonStr2 = "{\"id\":\"20190412\",\"name\":\"Iron Box\",\"price\":16.69}";
Product woodenBox = gson.fromJson(jsonStr1,Product.class);
Product ironBox = gson.fromJson(jsonStr2,Product.class);
/*
Product(id=20090804, name=Wooden Box, price=16.69)
Product(id=20190412, name=Iron Box, price=null)
*/
1
2
@SerializedName(value = "price",alternate = {"box_price","chest_price"})
private Double price;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Gson gson = new Gson();
String jsonStr1 = "{\"id\":\"20090804\",\"name\":\"Wooden Box\",\"box_price\":15.34}";
String jsonStr2 = "{\"id\":\"20190412\",\"name\":\"Case Box\",\"chest_price\":17.56}";
String jsonStr3 = "{\"id\":\"20200916\",\"name\":\"Iron Box\",\"price\":16.69}";
String jsonStr4 = "{\"id\":\"20050412\",\"name\":\"Box\",\"price\":16.6,\"box_price\":1.69,\"chest_price\":0.69}";
Product woodenBox = gson.fromJson(jsonStr1,Product.class);
Product caseBox = gson.fromJson(jsonStr2,Product.class);
Product ironBox = gson.fromJson(jsonStr3,Product.class);
Product box = gson.fromJson(jsonStr4,Product.class);
/*
Product(id=20090804, name=Wooden Box, price=15.34)
Product(id=20190412, name=Case Box, price=17.56)
Product(id=20200916, name=Iron Box, price=16.69)
Product(id=20050412, name=Box, price=0.69)


1
2
3
4
5
6
7
8
Gson gson = new Gson();
String jsonArray = "[\"Kotlin\",\"Groovy\",\"Scala\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>(){}.getType());
for(String str:strings){
System.out.println(str);
}
System.out.println(stringList.toString());

3.泛型

1
2
3
4
5
6
7
8
9
Gson gson = new Gson();
String jsonArray = "[\"Kotlin\",\"Groovy\",\"Scala\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>(){}.getType());
for(String str:strings){
System.out.println(str);
}
System.out.println(stringList.toString());

1
2
3
4
5
6
7
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
}
1
2
3
4
5
6
7
/*避免重复定义多个类*/
@ToString
public class Result<T> {
public int code;
public String message;
public T data;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Gson gson = new Gson();
Type userType = new TypeToken<Result<User>>(){}.getType();
Type userListType = new TypeToken<Result<List<User>>>(){}.getType();
/*

1.Gson提供TypeToken实现对泛型的支持
TypeToken的构造方法是protected修饰,即应该写为new TypeToken<List<String>>() {}.getType() 而非 new TypeToken<List<String>>().getType()
2.List<Object>的字节码文件只有List.class(泛型擦除),使用List<String> stringList = gson.fromJson(jsonArray, List.class);可以成功,即数据解析为List<String>不需要TypeToken,但泛型中除了基本类型和String可以成功外,但其他的会转为LinkedTreeMap丢失类型信息,同时这种方法也难以应付多种应用场景,难以减少冗余代码。
*/
String json = "{\"code\":\"200\",\"message\":\"success\",\"data\":{\"name\":\"Zha\",\"age\":12}}";
String jsonList = "{\"code\":\"404\",\"message\":\"Resource not found\",\"data\":[{\"name\":\"Li\",\"age\":19},{\"name\":\"Wu\",\"age\":25},{\"name\":\"Fu\",\"age\":35}]}";
Result<User> userResult = gson.fromJson(json,userType);
Result<List<User>> userListResult = gson.fromJson(jsonList,userListType);
List<User> users = userListResult.data;
System.out.println(userResult);
/*
Result(code=200, message=success, data=User(name=Zha, age=12))
User(name=Li, age=19)
User(name=Wu, age=25)
User(name=Fu, age=35)
*/

4.流式序列化和流式反序列化

1.流式序列化

  • 自动流式反序列化(Gson.fromJson(Reader,Class) Gson.fromJson(Reader,Type))
1
2
3
4
5
6
7
Gson gson = new Gson();
try (Reader reader = new FileReader("C:\\pro\\user.json")) {
User user = gson.fromJson(reader, User.class);
System.out.println(user);
} catch (IOException e) {
e.printStackTrace();
}
  • 手动流式反序列化

Gson提供了Stream包的JsonReader类来手动实现反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String json = "{\"name\":\"Zoom\",\"age\":\"24\"}";
User user = new User();
JsonReader reader = new JsonReader(new StringReader(json));
reader.beginObject();
while (reader.hasNext()) {
String str = reader.nextName();
switch (str) {
case "name":
user.setName(reader.nextString());
break;
case "age":
user.setAge(reader.nextInt());
break;
}
}
reader.endObject();
/*User(name=Zoom, age=24)*/

2.流式序列化

  • 自动流式序列化
    • toJson(Object src, Appendable writer)
    • toJson(Object src, Type typeOfSrc, Appendable writer)
    • toJson(JsonElement jsonElement, Appendable writer)

Appendable接口:PrintStream(System.out) StringBuilder StringBuffer*Writer

1
2
3
4
5
6
7
8
Gson gson = new Gson();
User user = new User("Pot",78);
gson.toJson(user,System.out);
/*{"name":"Pot","age":78}*/
/*
StringBuilder sb = new StringBuilder();
gson.toJson(user,sb);
*/
  • 手动流式序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
JsonWriter writer = new JsonWriter(new OutputStreamWriter(System.out));
writer.beginObject()
.name("name").value("Nike")
.name("age").value(11)
.name("email").nullValue()
.endObject();
writer.flush();
/*{"name":"Nike","age":11,"email":null}*/

writer.beginArray()
.value("Nike")
.value(11)
.nullValue()
.endArray();
writer.flush();
/*["Nike",11,null]*/
  • beginObject/endObjectbeginArray/endArray,两者可相互嵌套。

  • beginArray后不可以调用name方法,beginObject后在调用value之前必须要调用name方法。


5.GsonBuilder:构建Gson实例的类

1
2
Gson gson = new GsonBuilder()
.create();
1
2
3
4
5
Gson gson = new Gson();
System.out.println(gson.toJson(new User("Korie",67))); /*{"name":"Korie","age":67}*/
/*Gson默认不会导出值为null的键值对*/
Gson gson = new GsonBuilder().serializeNulls().create();
System.out.println(gson.toJson(new User("Korie",67))); /*{"name":"Korie","age":67,"email":null}*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Gson gson = new GsonBuilder()
/*序列化null*/
.serializeNulls()
/*设置日期时间格式*/
.setDateFormat("yyyy-MM-dd")
/*禁止序列化内部类 Inner Class*/
.disableInnerClassSerialization()
/*生成不可执行Json*/
.generateNonExecutableJson()
/*禁止转义html标签*/
.disableHtmlEscaping()
/*格式化输出*/
.setPrettyPrinting()
.create();

5.字段过滤

1
2
3
4
5
6
public class User {
private String name;
private Integer age;
private String email;
private Boolean isDeveloper;
}

1.@Expose

@Expose注解提供了两个属性:

  • deserialize:默认为true(反序列化生效)
  • serialize:默认为true(序列化生效)

需要和GsonBuilder使用,需要导出的字段上加上@Expose注解,不导出的字段不加。

1
2
3
4
5
6
7
8
9
10
public class User {
@Expose
private String name;
@Expose
private Integer age;
@Expose
private String email;
@Expose(deserialize = true,serialize = false)
private Boolean isDeveloper;
}
1
2
3
4
5
6
7
User user = new User("RIOT",22,"TestLib@gmail.com",true);
String ustr = "{\"name\":\"Rich\",\"age\":26,\"email\":\"TestLib2@gmail.com\",\"isDeveloper\":\"false\"}";
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
System.out.println(gson.toJson(user));
System.out.println(gson.fromJson(ustr,User.class));

2.@Since@Until

对基于版本的字段导出提供@Since@Until注解,和GsonBuilder.setVersion(Double)配合使用。当前版本(GsonBuilder设置版本) 大于等于Since的值时该字段导出,小于Until的值时该字段导出。当一个字段被@Since@Until同时注解时,需同时满足条件。

1
2
3
4
5
6
public class SinceUntilSample {
@Since(4)
private String since;
@Until(5)
private String until;
}
1
2
3
4
5
SinceUntilSample sinceUntilSample = new SinceUntilSample("since","until");
Gson gson = new GsonBuilder()
.setVersion(3.9)
.create();
System.out.println(gson.toJson(sinceUntilSample));

3.访问修饰符

GsonBuilder 提供 excludeFieldsWithModifiers方法,可自定义可忽略类型,参数为java.lang.reflect.Modifier类属性

1
2
3
4
5
6
7
8
public class ModifierSample {
final String finalField = "final";
static String staticField = "static";
public String publicField = "public";
protected String protectedField = "protected";
String defaultField = "default";
private String privateField = "private";
}
1
2
3
4
5
6
7
8
9
ModifierSample modifierSample = new ModifierSample();
/*
PUBLIC PRIVATE PROTECTED STATIC FINAL SYNCHRONIZED VOLATILE
TRANSIENT NATIVE INTERFACE ABSTRACT STRICT
*/
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC,Modifier.PUBLIC, Modifier.PROTECTED,Modifier.PRIVATE)
.create();
System.out.println(gson.toJson(modifierSample)); /*{"defaultField":"default"}*/

4.自定义过滤规则

GsonBuilderdeaddSerializationExclusionStrategyaddDeserializationExclusionStrategy 分别用于序列化和反序化(Gson提供的ExclusionStrategy接口)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ModifierSample modifierSample = new ModifierSample();
Gson gson = new GsonBuilder()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
if ("publicField".equals(f.getName())) return true; /*字段名排除 return true排除*/
Expose expose = f.getAnnotation(Expose.class);
if (expose != null && expose.deserialize() == false) return true; /*注解排除*/
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
/*直接排除类 ,return true排除*/
return (clazz == int.class || clazz == Integer.class);
}
})
.create();

6.字段映射规则

  • 默认实现

1.GsonBuilder

  • FieldNamingStrategy
  • setFieldNamingPolicy
  • setFieldNamingStrategy

2.@SerializedName 注解拥有最高优先级,有 @SerializedName 注解字段上 FieldNamingStrategy 无法生效。

2.GsonBuilder.setFieldNamingPolicy方法与枚举类FieldNamingPolicy配合使用。

FieldNamingPolicy 结果
IDENTITY 原格式
UPPER_CAMEL_CASE 首个字母大写
UPPER_CAMEL_CASE_WITH_SPACES 空格隔开
LOWER_CASE_WITH_UNDERSCORES 下划线隔开
LOWER_CASE_WITH_DASHES 中间线隔开
LOWER_CASE_WITH_DOTS 点号隔开
1
2
3
4
5
public class User {
private String name;
private Integer age;
private String emailAddress;
}
1
2
3
4
5
6
User user = new User("VK",23,"Test@gmail.com");
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DOTS)
.create();
System.out.println(gson.toJson(user));
/*{"name":"VK","age":23,"email.address":"Test@gmail.com"}*/
  • 自定义实现

GsonBuilder.setFieldNamingStrategy 方法需要与Gson提供的FieldNamingStrategy接口配合使用,用于将POJO字段与JSON字段对应,FieldNamingPolicy也可以使用setFieldNamingStrategy方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
User user = new User("VK",23,"Test@gmail.com");
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new FieldNamingStrategy() {
@Override
public String translateName(Field field) {
if ("emailAddress".equals(field.getName())) {
return "email";
}
return field.getName();
}
})
.create();
System.out.println(gson.toJson(user));
/*{"name":"VK","age":23,"email":"Test@gmail.com"}*/

7.TypeAdapter

1.TypeAdapter是Gson自2.0开始提供的一个抽象类,用于接管某种类型的序列化和反序列化过程,包含两个注要方法write(JsonWriter,T)read(JsonReader)其它方法都是final方法并最终调用这两个抽象方法。

2.TypeAdapter 以及 JsonSerializer 和 JsonDeserializer 都需要与GsonBuilder.registerTypeAdapterGsonBuilder.registerTypeHierarchyAdapter配合使用。

jsonWrite方法 jsonWriter写入字符
beginArray [
endArray ]
beginObject {
endObject }
1
2
3
4
5
public class User {
private String name;
private Integer age;
private String email;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public abstract class TypeAdapter<T> {
public TypeAdapter() {
}

public abstract void write(JsonWriter var1, T var2) throws IOException;

public final void toJson(Writer out, T value) throws IOException {
JsonWriter writer = new JsonWriter(out);
this.write(writer, value);
}

public final TypeAdapter<T> nullSafe() {
return new TypeAdapter<T>() {
public void write(JsonWriter out, T value) throws IOException {
if (value == null) {
out.nullValue();
} else {
TypeAdapter.this.write(out, value);
}

}

public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
} else {
return TypeAdapter.this.read(reader);
}
}
};
}

public final String toJson(T value) {
StringWriter stringWriter = new StringWriter();

try {
this.toJson(stringWriter, value);
} catch (IOException var4) {
throw new AssertionError(var4);
}

return stringWriter.toString();
}

public final JsonElement toJsonTree(T value) {
try {
JsonTreeWriter jsonWriter = new JsonTreeWriter();
this.write(jsonWriter, value);
return jsonWriter.get();
} catch (IOException var3) {
throw new JsonIOException(var3);
}
}

public abstract T read(JsonReader var1) throws IOException;

public final T fromJson(Reader in) throws IOException {
JsonReader reader = new JsonReader(in);
return this.read(reader);
}

public final T fromJson(String json) throws IOException {
return this.fromJson((Reader)(new StringReader(json)));
}

public final T fromJsonTree(JsonElement jsonTree) {
try {
JsonReader jsonReader = new JsonTreeReader(jsonTree);
return this.read(jsonReader);
} catch (IOException var3) {
throw new JsonIOException(var3);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class UserTypeAdapter extends TypeAdapter<User> {
@Override
public void write(JsonWriter jsonWriter, User user) throws IOException {
jsonWriter.beginObject();
jsonWriter.name("name").value(user.getName());
jsonWriter.name("age").value(user.getAge());
jsonWriter.name("emailAddress").value(user.getEmail());
jsonWriter.endObject();
}

@Override
public User read(JsonReader jsonReader) throws IOException {
User user = new User();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
switch (jsonReader.nextName()) {
case "name":
user.setName(jsonReader.nextString());
break;
case "age":
user.setAge(jsonReader.nextInt());
break;
case "emailAddress":
user.setEmail(jsonReader.nextString());
break;
}
}
jsonReader.endObject();
return user;
}
}
1
2
3
4
5
6
7
8
User user = new User("Gori", 72,"Gori101@gamil.com");
Gson gson = new GsonBuilder()
/*User注册TypeAdapter*/
.registerTypeAdapter(User.class, new UserTypeAdapter())
.create();
System.out.println(gson.toJson(user));
String str = "{\"name\":\"vita\",\"age\":43,\"emailAddress\":\"VitaOne@gamil.com\"}";
System.out.println(gson.fromJson(str,User.class));

8.JsonSerializer与JsonDeserializer

Gson 使用 JsonSerializer 接管序列化过程,JsonDeserializer 接管反序列化过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Gson gson = new GsonBuilder()
.registerTypeAdapter(Integer.class, new JsonDeserializer<Integer>() {
@Override
public Integer deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
try{
int value = jsonElement.getAsInt();
if (value>=24){
return value%24;
}
return value;
/*异常数字转换为-1*/
}catch (NumberFormatException e) {
return -1;
}
}
})
.create();
System.out.println(gson.fromJson("10",Integer.class)); /*10*/
System.out.println(gson.fromJson("1023",Integer.class)); /*15*/
System.out.println(gson.fromJson("err",Integer.class)); /*-1*/
System.out.println(gson.fromJson("\"\"",Integer.class)); /*-1*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*数字序列化*/
JsonSerializer<Number> numberJsonSerializer = new JsonSerializer<Number>() {
@Override
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(String.valueOf(src));
}
};
/*字符串序列化*/
JsonSerializer<String> stringJsonSerializer = new JsonSerializer<String>() {
@Override
public JsonElement serialize(String arg0, Type arg1, JsonSerializationContext arg2) {
return new JsonPrimitive(arg0 + "_ADD");
}
};
Gson strGson = new GsonBuilder()
.registerTypeAdapter(String.class, stringJsonSerializer)
.create();
System.out.println(strGson.toJson("JSON"));
/*
1.registerTypeAdapter必须使用包装类型
2.不能使用父类代替其子类型,即不能直接使用Number.class
*/
Gson numberGson = new GsonBuilder()

.registerTypeAdapter(Integer.class, numberJsonSerializer)
.registerTypeAdapter(Long.class, numberJsonSerializer)
.registerTypeAdapter(Float.class, numberJsonSerializer)
.registerTypeAdapter(Double.class, numberJsonSerializer)
.create();
System.out.println(numberGson.toJson(100.0f));
/*registerTypeHierarchyAdapter可直接使用Number.class*/
Gson numberGsonWitheHierarchy = new GsonBuilder()
.registerTypeHierarchyAdapter(Number.class, numberJsonSerializer)
.create();
System.out.println(numberGsonWitheHierarchy.toJson(100.01));
/*"JSON_ADD"*/
/*"100.0"*/
/*100.01"*/

1.registerTypeAdapter支持泛型,registerTypeHierarchyAdapter支持继承。

2.如果一个被序列化的对象本身带有泛型且注册相应的TypeAdapter,那么必须调用Gson.toJson(Object,Type),明确告诉Gson对象类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Type type= new TypeToken<List<User>>(){}.getType();
TypeAdapter typeAdapter = new TypeAdapter<List<User>>() {
@Override
public void write(JsonWriter jsonWriter, List<User> users) throws IOException {
jsonWriter.beginArray();
for(User user:users){
jsonWriter.beginObject();
jsonWriter.name("name").value(user.getName());
jsonWriter.name("age").value(user.getAge());
jsonWriter.name("emailAddress").value(user.getEmail());
jsonWriter.endObject();
}
jsonWriter.endArray();
}

@Override
public List<User> read(JsonReader jsonReader) throws IOException {
return null;
}
};

Gson gson = new GsonBuilder()
.registerTypeAdapter(type, typeAdapter)
.create();
List<User> list = new ArrayList<>();
list.add(new User("T1",11,"t1User@qq.com"));
list.add(new User("T2",22,"t2User@qq.com"));
String result = gson.toJson(list, type);
System.out.println(result);
/*
[{"name":"T1","age":11,"emailAddress":"t1User@qq.com"},{"name":"T2","age":22,"emailAddress":"t2User@qq.com"}]
*/

9.TypeAdapterFactory

可用于创建TypeAdapter的工厂类,通过对比Type,确定有无对应的TypeAdapter,没有返回null。

1
2
3
4
5
6
7
8
9
10
11
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
if(typeToken.getType().equals(type)){
return typeAdapter;
}
return null;
}
})
.create();
  • CollectionTypeAdapterFactory中的create方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType();
if (!Collection.class.isAssignableFrom(rawType)) {
return null;
} else {
Type elementType = Types.getCollectionElementType(type, rawType);
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
ObjectConstructor<T> constructor = this.constructorConstructor.get(typeToken);
TypeAdapter<T> result = new CollectionTypeAdapterFactory.Adapter(gson, elementType, elementTypeAdapter, constructor);
return result;
}
}

10.JsonAdapter

1.JsonAdapter注解位于POJO类上,接收一个参数且必须是

  • TypeAdpater

  • TypeAdapterFactory

  • JsonSerializer

  • JsonDeserializer

且JsonAdapter无需使用GsonBuilder进行注册。

2.JsonAdapter的优先级比GsonBuilder.registerTypeAdapter的优先级更高。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class UserTypeAdapter extends TypeAdapter<User> {
@Override
public void write(JsonWriter jsonWriter, User user) throws IOException {
jsonWriter.beginObject();
jsonWriter.name("name").value(user.getName());
jsonWriter.name("age").value(user.getAge());
jsonWriter.name("email_Address").value(user.getEmail());
jsonWriter.endObject();
}

@Override
public User read(JsonReader jsonReader) throws IOException {
User user = new User();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
switch (jsonReader.nextName()) {
case "name":
user.setName(jsonReader.nextString());
break;
case "age":
user.setAge(jsonReader.nextInt());
break;
case "emailAddress":
user.setEmail(jsonReader.nextString());
break;
}
}
jsonReader.endObject();
return user;
}
}
1
2
3
4
Gson gson = new Gson();
User user = new User("SOM", 74, "SONM@qq.com");
System.out.println(gson.toJson(user));
/*{"name":"SOM","age":74,"email_Address":"SONM@qq.com"}*/


Pojo Bean

What is java pojo class, java bean, normal class?

1.Java Beans:

  • All properties private (use getters/setters)
  • A public no-argument constructor
  • Implements Serializable.

2.Pojo: Plain Old Java Object is a Java object not bound by any restriction other than those forced by the Java Language Specification. I.e., a POJO should not have to

  • Extend prespecified classes
  • Implement prespecified interface
  • Contain prespecified annotations

POJO通常是不需要是任何类的子类和实现特定的接口以及遵循特定的模式。