从 ObjectInputStream 反序列化为子类之一
Deserialize from ObjectInputStream to one of the subclasses
我有一个名为 Message
的摘要 class:
public abstract class Message
{
public enum MsgType
{
TypeA, TypeB
}
public String Sender;
public MsgType Type;
}
其中有两个子classes:
public class MessageA extends Message
{
public String A;
public MessageA()
{
Type = MsgType.TypeA;
}
}
public class MessageB extends Message
{
public int B;
public MessageB()
{
Type = MsgType.TypeB;
}
}
我想通过实例化 MessageA
或 MessageB
使用 Simple 库直接从 ObjectsInputStream
反序列化对象,具体取决于从流中读取的对象。
我试过这样做:
inputStream = new ObjectInputStream(clientSocket.getInputStream());
Message msg = serializer.read(Message.class, inputStream);
// check whether it's MessageA or MessageB by checking Type
但它不起作用,因为编译器无法将 MessageA
或 MessageB
反序列化为 Message
class。另外,我很确定我会在这个过程中丢失 subclass' 字段。
有什么正确的方法吗?
public class Main {
public static void main( String[] args ) throws Exception {
Serializer serializer = new Persister();
MessageB messageB = new MessageB( "example", 123 );
File result = new File( "example.xml" );
serializer.write( messageB, result );
MessageB msgB = serializer.read( MessageB.class, result );
System.out.println( msgB );
try {
if( serializer.validate( MessageA.class, result ) ){
System.out.println( "valid for MessageA" );
}
} catch( Exception e ){
System.out.println( "NOT valid for MessageA" );
}
try {
if( serializer.validate( MessageB.class, result ) ){
System.out.println( "valid for MessageB" );
}
} catch( Exception e ){
System.out.println( "NOT valid for MessageB" );
}
}
}
public abstract class Message{
public enum MsgType {
TypeA, TypeB
}
@Element
private String sender;
@Element
private MsgType type;
protected Message(){
}
protected Message( String s, MsgType t ){
sender = s;
type = t;
}
public String getSender(){ return sender; }
public MsgType getType(){ return type; }
public String toString(){
return "type=" + type + ", sender=" + sender;
}
}
@Root
public class MessageA extends Message {
@Element
private String a;
public MessageA(){
}
public MessageA( String s, String a ){
super( s, MsgType.TypeA );
this.a = a;
}
public String getA(){ return a; }
public String toString(){
return super.toString() + ", a=" + a;
}
}
@Root
public class MessageB extends Message {
@Element
private int b;
public MessageB(){
}
public MessageB( String s, int b ){
super( s, MsgType.TypeA );
this.b = b;
}
public int getB(){ return b; }
public String toString(){
return super.toString() + ", b=" + b;
}
}
这个效果很好。
type=TypeA, sender=example, b=123
NOT valid for MessageA
valid for MessageB
XML文件写成:
<messageB>
<sender>example</sender>
<type>TypeA</type>
<b>123</b>
</messageB>
为每个子类添加一个@Root(name = "...") 注释
例如:
public interface StringOperation {
String performOperation(String input);
}
@Root(name = "upperCaseStringOperation")
public class UpperCaseStringOperation implements StringOperation {
public UpperCaseStringOperation() {
}
@Override
public String performOperation(String input) {
return (input == null) ? (null) : (input.toUpperCase());
}
}
@Root(name = "lowerCaseStringOperation")
public class LowerCaseStringOperation implements StringOperation {
public LowerCaseStringOperation() {
}
@Override
public String performOperation(String input) {
return (input == null) ? (null) : (input.toLowerCase());
}
}
@Root(name = "noOpStringOperation")
public class NoOpStringOperation implements StringOperation {
public NoOpStringOperation() {
}
@Override
public String performOperation(String input) {
return input;
}
}
@Root
public class Data {
@Element
private String name;
@Element
private StringOperation nameOperation;
@Element
private String email;
@Element
private StringOperation emailOperation;
public Data() {
nameOperation = new NoOpStringOperation();
emailOperation = new NoOpStringOperation();
}
public String getName() {
return name;
}
public String getProcessedName() {
return nameOperation.performOperation(getName());
}
public String getEmail() {
return email;
}
public String getProcessedEmail() {
return emailOperation.performOperation(getEmail());
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setNameOperation(StringOperation operation) {
this.nameOperation = operation;
}
public void setEmailOperation(StringOperation operation) {
this.emailOperation = operation;
}
@Override
public String toString() {
return String.format("Data(name = %s, processedName = %s, email = %s, processedEmail = %s)",
getName(),
getProcessedName(),
getEmail(),
getProcessedEmail());
}
}
示例代码:
Data before = new Data();
before.setName("Joseph Wallflower");
before.setNameOperation(new UpperCaseStringOperation());
before.setEmail("Joseph.Wallflower@SomeCompany.com");
before.setEmailOperation(new LowerCaseStringOperation());
System.out.format("BEFORE: %s%n", before.toString());
Serializer serializer = new Persister();
File file = new File(System.getenv("USERPROFILE")+File.separator+"Documents"+File.separator+"simple.xml");
serializer.write(before, file);
结果:
<data>
<name>Joseph Wallflower</name>
<nameOperation class="simplexml.UpperCaseStringOperation"/>
<email>Joseph.Wallflower@SomeCompany.com</email>
<emailOperation class="simplexml.LowerCaseStringOperation"/>
</data>
我有一个名为 Message
的摘要 class:
public abstract class Message
{
public enum MsgType
{
TypeA, TypeB
}
public String Sender;
public MsgType Type;
}
其中有两个子classes:
public class MessageA extends Message
{
public String A;
public MessageA()
{
Type = MsgType.TypeA;
}
}
public class MessageB extends Message
{
public int B;
public MessageB()
{
Type = MsgType.TypeB;
}
}
我想通过实例化 MessageA
或 MessageB
使用 Simple 库直接从 ObjectsInputStream
反序列化对象,具体取决于从流中读取的对象。
我试过这样做:
inputStream = new ObjectInputStream(clientSocket.getInputStream());
Message msg = serializer.read(Message.class, inputStream);
// check whether it's MessageA or MessageB by checking Type
但它不起作用,因为编译器无法将 MessageA
或 MessageB
反序列化为 Message
class。另外,我很确定我会在这个过程中丢失 subclass' 字段。
有什么正确的方法吗?
public class Main {
public static void main( String[] args ) throws Exception {
Serializer serializer = new Persister();
MessageB messageB = new MessageB( "example", 123 );
File result = new File( "example.xml" );
serializer.write( messageB, result );
MessageB msgB = serializer.read( MessageB.class, result );
System.out.println( msgB );
try {
if( serializer.validate( MessageA.class, result ) ){
System.out.println( "valid for MessageA" );
}
} catch( Exception e ){
System.out.println( "NOT valid for MessageA" );
}
try {
if( serializer.validate( MessageB.class, result ) ){
System.out.println( "valid for MessageB" );
}
} catch( Exception e ){
System.out.println( "NOT valid for MessageB" );
}
}
}
public abstract class Message{
public enum MsgType {
TypeA, TypeB
}
@Element
private String sender;
@Element
private MsgType type;
protected Message(){
}
protected Message( String s, MsgType t ){
sender = s;
type = t;
}
public String getSender(){ return sender; }
public MsgType getType(){ return type; }
public String toString(){
return "type=" + type + ", sender=" + sender;
}
}
@Root
public class MessageA extends Message {
@Element
private String a;
public MessageA(){
}
public MessageA( String s, String a ){
super( s, MsgType.TypeA );
this.a = a;
}
public String getA(){ return a; }
public String toString(){
return super.toString() + ", a=" + a;
}
}
@Root
public class MessageB extends Message {
@Element
private int b;
public MessageB(){
}
public MessageB( String s, int b ){
super( s, MsgType.TypeA );
this.b = b;
}
public int getB(){ return b; }
public String toString(){
return super.toString() + ", b=" + b;
}
}
这个效果很好。
type=TypeA, sender=example, b=123
NOT valid for MessageA
valid for MessageB
XML文件写成:
<messageB>
<sender>example</sender>
<type>TypeA</type>
<b>123</b>
</messageB>
为每个子类添加一个@Root(name = "...") 注释
例如:
public interface StringOperation {
String performOperation(String input);
}
@Root(name = "upperCaseStringOperation")
public class UpperCaseStringOperation implements StringOperation {
public UpperCaseStringOperation() {
}
@Override
public String performOperation(String input) {
return (input == null) ? (null) : (input.toUpperCase());
}
}
@Root(name = "lowerCaseStringOperation")
public class LowerCaseStringOperation implements StringOperation {
public LowerCaseStringOperation() {
}
@Override
public String performOperation(String input) {
return (input == null) ? (null) : (input.toLowerCase());
}
}
@Root(name = "noOpStringOperation")
public class NoOpStringOperation implements StringOperation {
public NoOpStringOperation() {
}
@Override
public String performOperation(String input) {
return input;
}
}
@Root
public class Data {
@Element
private String name;
@Element
private StringOperation nameOperation;
@Element
private String email;
@Element
private StringOperation emailOperation;
public Data() {
nameOperation = new NoOpStringOperation();
emailOperation = new NoOpStringOperation();
}
public String getName() {
return name;
}
public String getProcessedName() {
return nameOperation.performOperation(getName());
}
public String getEmail() {
return email;
}
public String getProcessedEmail() {
return emailOperation.performOperation(getEmail());
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setNameOperation(StringOperation operation) {
this.nameOperation = operation;
}
public void setEmailOperation(StringOperation operation) {
this.emailOperation = operation;
}
@Override
public String toString() {
return String.format("Data(name = %s, processedName = %s, email = %s, processedEmail = %s)",
getName(),
getProcessedName(),
getEmail(),
getProcessedEmail());
}
}
示例代码:
Data before = new Data();
before.setName("Joseph Wallflower");
before.setNameOperation(new UpperCaseStringOperation());
before.setEmail("Joseph.Wallflower@SomeCompany.com");
before.setEmailOperation(new LowerCaseStringOperation());
System.out.format("BEFORE: %s%n", before.toString());
Serializer serializer = new Persister();
File file = new File(System.getenv("USERPROFILE")+File.separator+"Documents"+File.separator+"simple.xml");
serializer.write(before, file);
结果:
<data>
<name>Joseph Wallflower</name>
<nameOperation class="simplexml.UpperCaseStringOperation"/>
<email>Joseph.Wallflower@SomeCompany.com</email>
<emailOperation class="simplexml.LowerCaseStringOperation"/>
</data>