关于对象序列化、jackson以及jackson和cxf配合使用的一些心得体、对象克隆、对象深度复制...

本文探讨了Java序列化的基本概念及其应用场景,并通过实例演示了序列化与反序列化的操作流程。此外,还介绍了对象克隆及深度复制的实现方法,并讨论了cxf与jackson在RESTful API中的应用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

    趁着周末学习一番,目标如下:


  • 明白什么事java序列化,如何进行java序列化和反序列化
  • 对jackson工具包系统的学习,从了json转换外还有没有其他好用的功能,jackson和cxf如何更好的派和使用
  • java对象克隆的使用场景在哪儿,如何通过克隆进行java的深度复制


二、对象序列化(object serialization)

1、概念

java的向对象序列化API,它提供了一个框架,用来将对象编码成字节流,并从字节流编码中重新构建对象。“将一个对象编码成一个字节流”称作将改对象序列化(serializing) ;相反处理过程被称作反序列化(deserializing)。

2、java序列化的要点


  • 你可以通过序列化来存储对象的状态
  • 使用ObjectOutPutStream来序列化对象(Java.IO)
  • 用FileOutPutStream链接ObjectOutPutStream来讲对象序列化到文件中
  • 调用ObjectOutPutStream的writeObject(the object) 来将对象序列化,不需调用FileOutPutStream的方法
  • 静态变量 不会被序列化,因为所有对象都是共享同一份静态变量值


3、例子将person对象反序列化


package com.fengshu.Spring;

import java.io.Serializable;

public class Person implements Serializable {

	private static final long serialVersionUID = 1L;

	private String name;
	private int age;

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "对象序列化 [name=" + name + ", age=" + age + "]";
	}

}




package com.fengshu.Spring;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;


public class SeriableTest {
  public static void main(String[] args) throws Exception {  
        File file = new File("E:\\result.txt");  //如果不存在会被创建
        ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));  
        Person person = new Person("John", 101);  
        oout.writeObject(person);  
        oout.close();  
  
        ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));  
        Person newPerson = (Person)oin.readObject();
        oin.close();  
        System.out.println(newPerson);  
    }  
}


  
  




二、对象克隆和深度复制

1、以订单为例,下面是一组订单相关的对象,这些对象装在一个clone对象里面

订单对象


package com.fengshu.Spring;

import java.util.List;

public class Order {
	@Override
	public String toString() {
		return "Order [name=" + name + ", orderItems=" + orderItems + "]";
	}

	private String name;
	private List<OrderItem> orderItems;

	public String getName() {
		return name;
	}

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

	public List<OrderItem> getOrderItems() {
		return orderItems;
	}

	public void setOrderItems(List<OrderItem> orderItems) {
		this.orderItems = orderItems;
	}

}



订单详细对象 



package com.fengshu.Spring;

public class OrderItem {
	@Override
	public String toString() {
		return "OrderItem [name=" + name + ", price=" + price + "]";
	}

	private String name;
	private double  price;

	public String getName() {
		return name;
	}

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

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}
	
	
}



订单结算对象


在实际项目中假设以上两个对象用于跟数据库打交道,很多时候我们为了解耦,我们会建立另外一组用于业务逻辑的对象 。如下:

用于业务逻辑的订单对象


package com.fengshu.Spring;

import java.util.List;

public class OrderDTO {
	@Override
	public String toString() {
		return "OrderDTO [name=" + name + ", orderItems=" + orderItems + "]";
	}

	private String name;
	private List<OrderItemDTO> orderItems;

	public String getName() {
		return name;
	}

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

	public List<OrderItemDTO> getOrderItems() {
		return orderItems;
	}

	public void setOrderItems(List<OrderItemDTO> orderItems) {
		this.orderItems = orderItems;
	}

}



用于业务逻辑的订单详细对象



package com.fengshu.Spring;

public class OrderItemDTO {
	@Override
	public String toString() {
		return "OrderItemDTO [name=" + name + "]";
	}

	private String name;

	public String getName() {
		return name;
	}

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


用于业务逻辑的订单结算对象

package com.fengshu.Spring;

import java.util.List;

public class SettleOrderDTO {
	@Override
	public String toString() {
		return "SettleOrderDTO [name=" + name + ", orders=" + orders + "]";
	}
	private String  name;
	private List<OrderDTO> orders;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List<OrderDTO> getOrders() {
		return orders;
	}
	public void setOrders(List<OrderDTO> orders) {
		this.orders = orders;
	}
	
	
}



2、那么问题来了,我们如何一次性的把SettleOrderView里面的内容复制给SettleOrderDTO ,使用过apache或spring的beanUtils工具类的开发人员都知道beanutils在copy对象的过程中是不会帮忙copy对象里面的复杂属性的,即所谓的浅复制,那么如何进行深度复制呢,有一个办法是通过json字符串作为中间对象来进行转换,


3、json方式如下

package com.fengshu.Spring;

import java.util.ArrayList;
import java.util.List;

public class Clone {
	
	
	private  static List<OrderItem> orderItems =  new ArrayList<OrderItem>();
	
	private static List<Order> orders = new ArrayList<Order>();
	
	static SettlerOrderView settlerOrderView = new SettlerOrderView();
	
	static {
		init();
	}
	
	
	public static  void init() {
		OrderItem orderItem = new OrderItem();
		orderItem.setName("orderitem");
		orderItems.add(orderItem);
		
		Order order = new Order();
		order.setName("order");
		order.setOrderItems(orderItems);
		orders.add(order);
		settlerOrderView.setName("settlerOrderView");
		settlerOrderView.setOrders(orders);
	}
	
	public static void main(String[] args) {
		try {
			String jsonStr = JsonUtils.toJson(settlerOrderView);
			System.out.println(jsonStr);
			
			SettleOrderDTO  settleOrderDTO  =  JsonUtils.getObjectMapper().readValue(jsonStr, SettleOrderDTO.class);
			
			jsonStr = JsonUtils.toJson(settleOrderDTO);
			System.out.println(jsonStr);//price 为0  被忽略了 
		} catch (Exception e) {
			// TODO: handle exception
		}
		
	}
}



json工具类
package com.fengshu.Spring;

import java.io.IOException;

import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;

public class JsonUtils {

	public static final String MESSAGE = "message";

	@SuppressWarnings("unused")
	private static JsonGenerator jsonGenerator;

	private static ObjectMapper objectMapper;

	@SuppressWarnings("deprecation")
	private static void init() {
		objectMapper = new ObjectMapper();
		objectMapper.getSerializationConfig().setSerializationInclusion(Inclusion.ALWAYS);
		objectMapper.getDeserializationConfig().set(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		try {
			jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(System.out, JsonEncoding.UTF8);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static ObjectMapper getObjectMapper() {
		if (objectMapper == null) {
			init();
		}
		return objectMapper;
	}

	public static String toJson(Object obj) throws JsonGenerationException, JsonMappingException, IOException {
		return getObjectMapper().writeValueAsString(obj);
	}

	public static <T> T formJson(JsonNode json, Class<T> clazz) throws JsonParseException, JsonMappingException, IOException {
		return getObjectMapper().readValue(json, clazz);
	}

}



4、通过实现clonable来实现对象的深度复制

经实践发现两个不同类的实例对象,即使克隆后好像也不能强制转换,apache的beanutils的cloneBean方法也会报错,还没找到一个好的方案 ,java的大部分资料也很少讨论克隆,如果有人实现了,希望可以交流下。


三、cxf和jackson  

在cxf和jackson的配合使用中有以几点心得

1、客户端和服务器端对象之间的传递和返回最后使用json格式

 尽量避免以xml的格式来进行对象之间的传递,先不说性能问题,但是使用的复杂性就足以让人望而却步,更重要的是使用xml格式进行对象传递返回的话,需要遵循一大堆的规范,一不小心就报错,而且可能报一个你需要长时间才能找到原因的错误


2、cxf报错的解决步骤

先让自己的cxf发布和调用遵循第一个原则,然后在检查是否遵循相关的规范,比如如果cxf的参数是复杂对象的话cxf必须设置为post请求,get请求将会报错,类似于参数Too long的错误


3、json转换的时候最好忽略null和未知对象

为避免不必要的错误,且减少一些空的属性的传递,最后设置为负率null,可通过注解和xml配置,建议使用第二种方案,第二种方案只需要配置一次就可以了,第一种方案需要给每个pojo加上注解.


4、jackson在转换过长中目前并不支持timestamp 和map作为参数

apache的所有工具类几乎都在不同场景不支持timestamp,不知道什么原因,至于map应该是因为本身结构太复杂了吧,可以通过是配置来解决此问题


5、关于复杂对象的传递

   对象里面如果包裹复杂对象原则上是可以传递的,此种情况强烈建议使用json格式进行对象传输和返回,否则需要进行一系列复杂的注解来进行支持,很多时候这些注解你只知其然而不知道其所以然,所以很容易忘掉。

post请求如需要以json格式传输,必须强制指定传递格式为json

@Consumes(MediaType.APPLICATION_JSON)







6、梯子

关于cxf使用的博文 http://my.oschina.net/fengshuzi/blog/280408


















转载于:https://my.oschina.net/fengshuzi/blog/418976

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值