de.tsl2.nano.bean.def.Extension Maven / Gradle / Ivy
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Tom
* created on: 01.03.2014
*
* Copyright: (c) Thomas Schneider 2014, all rights reserved
*/
package de.tsl2.nano.bean.def;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.ElementMap;
import org.simpleframework.xml.Transient;
import org.simpleframework.xml.core.Commit;
import de.tsl2.nano.bean.BeanUtil;
import de.tsl2.nano.core.cls.BeanClass;
import de.tsl2.nano.core.cls.PrivateAccessor;
import de.tsl2.nano.util.operation.IConverter;
/**
* Workaround for de-/serializings through simple-xml. while you must know the type of your deserializing root element,
* it is not possible, to load any class-extensions.
*
* This class can be used as member of your base-class. after deserializing you can create the desired extension
* instance through informations of this extension-instance.
*
* USE:
*
*
* - mark all extending members with annotation {@link Transient} (not with javas keyword 'transient')
* - on serialization of your extension class, call {@link #Extension(Object)} in your method annotated with {@link Commit}.
* {AT}Persist
* protected void initSerialization() {
* extension = new Extension(this);
* if (extension.isEmpty())
* extension = null;
* }
* - on de-serialization, call {@link #to(Object)} getting the desired instance.
*
*
* @author Tom
* @version $Revision$
*/
public class Extension implements Serializable, IConverter {
/** serialVersionUID */
private static final long serialVersionUID = -3429339914632368033L;
/**
* while there are problems on simple-xml serializing an own extension of hashmap, we use it only as member-variable
*/
@ElementMap(entry = "member", attribute = true, inline = true, required = false, empty = true, keyType = String.class, key = "name")
private LinkedHashMap members;
/** only used to check type by generics */
protected transient Class baseClass;
/** extension class - has to have a default constructor */
@Attribute
protected Class declaringClass;
/**
* constructor
*/
protected Extension() {
super();
}
/**
* constructor
*
* @param baseClass
* @param declaringClass
*/
protected Extension(Class baseClass, Class declaringClass) {
super();
this.baseClass = baseClass;
this.declaringClass = declaringClass;
}
/**
* evaluates the given instance and stores all found members, having the Annotation {@link Transient} but is
* implementing {@link Serializable}.
*
* @param extInstance instance to prepare for serialization
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public Extension(EXT extInstance) {
declaringClass = (Class) extInstance.getClass();
PrivateAccessor extAcc = new PrivateAccessor(extInstance);
List members = extAcc.memberNames(Transient.class);
Object value;
for (String m : members) {
value = extAcc.member(m);
if (value != null && Serializable.class.isAssignableFrom(value.getClass())) {
members().put(m, value);
}
}
}
private final LinkedHashMap members() {
if (members == null) {
members = new LinkedHashMap();
}
return members;
}
/**
* @return Returns the declaringClass.
*/
protected Class getDeclaringClass() {
return declaringClass;
}
@Override
public BASE from(EXT toValue) {
throw new UnsupportedOperationException();
}
@Override
public EXT to(BASE fromValue) {
EXT ext = BeanClass.createInstance(declaringClass);
PrivateAccessor extAcc = new PrivateAccessor(ext);
BeanUtil.copy(fromValue, ext);
Set keys = members().keySet();
for (String member : keys) {
extAcc.set(member, members().get(member));
}
//TODO: eval the right method name having annotation 'Commit'.
extAcc.call("initDeserialization", Void.class);
return ext;
}
public boolean isEmpty() {
return members().isEmpty();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy