/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.serialization; import org.openmrs.ImplementationId; import org.openmrs.Patient; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; /** * This serializer uses the xstream library to serialize and deserialize objects. * <br/> * All classes are automatically aliased. So a serialization of the {@link Patient} class * will not be: * <code> * <org.openmrs.Patient ...> * <element * ... * </org.openmrs.Patient> * </code> * but instead will be: * <code> * <patient ...> * <element * ... * </patient> * </code> * */ public class SimpleXStreamSerializer implements OpenmrsSerializer { // cached xstream object public XStream xstream = null; /** * Default Constructor * * @throws SerializationException */ public SimpleXStreamSerializer() throws SerializationException { this(null); } /** * Constructor that takes a custom XStream object * @param xstream * @throws SerializationException */ public SimpleXStreamSerializer(XStream customXstream) throws SerializationException { if (customXstream == null) { xstream = new XStream(new DomDriver()); } else { this.xstream = customXstream; } //this is added to read the prior simpleframework-serialized values. // TODO find a better way to do this. this.xstream.useAttributeFor(ImplementationId.class, "implementationId"); } /** * alias className for class "c", we will use such a form, alias "user" for * "org.openmrs.User.class". The alias principle is to low the first letter of the simple name * of class "c" Note: if in module have a few new classes need to be serialize, call this method * for each new class will automatically alias className for them * * @param c - the class need to alias its className */ private void aliasClassName(Class<?> c) { //through Class.getSimpleName(), we get the short name of a class, such as get "User" for class "org.openmrs.User" String simpleName = c.getSimpleName(); String firstLetter = simpleName.substring(0, 1); String leftName = simpleName.substring(1); String aliasName = firstLetter.toLowerCase() + leftName; xstream.alias(aliasName, c); } /** * Expose the xstream object, so that module can config with xstream as need * * @return xstream can be configed by module */ public XStream getXstream() { return xstream; } /** * @see OpenmrsSerializer#serialize(java.lang.Object) */ public String serialize(Object o) throws SerializationException { aliasClassName(o.getClass()); return xstream.toXML(o); } /** * @see OpenmrsSerializer#deserialize(String, Class) */ @SuppressWarnings("unchecked") public <T extends Object> T deserialize(String serializedObject, Class<? extends T> clazz) throws SerializationException { if (clazz != null) { aliasClassName(clazz); } return (T) xstream.fromXML(serializedObject); } }