/* * Copyright (C) 2012, 2016 higherfrequencytrading.com * Copyright (C) 2016 Roman Leventov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.xstream.converters; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import net.openhft.chronicle.values.ArrayFieldModel; import net.openhft.chronicle.values.FieldModel; import net.openhft.chronicle.values.ValueModel; import net.openhft.chronicle.values.Values; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author Rob Austin. */ public class ValueConverter implements Converter { private static final Logger LOG = LoggerFactory.getLogger(ValueConverter.class); @Override public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext context) { ValueModel valueModel = ValueModel.acquire(o.getClass()); valueModel.fields().forEach(fieldModel -> { if (fieldModel instanceof ArrayFieldModel) { try { final Method indexedGet = fieldModel.getOrGetVolatile(); indexedGet.setAccessible(true); writer.startNode(fieldModel.name()); for (int i = 0; i < ((ArrayFieldModel) fieldModel).array().length(); i++) { writer.startNode(Integer.toString(i)); context.convertAnother(indexedGet.invoke(o, i)); writer.endNode(); } writer.endNode(); } catch (IllegalAccessException | InvocationTargetException e) { throw new ConversionException("", e); } return; } try { final Method get = fieldModel.getOrGetVolatile(); get.setAccessible(true); final Object value = get.invoke(o); writer.startNode(fieldModel.name()); context.convertAnother(value); writer.endNode(); } catch (Exception e) { LOG.error("class=" + fieldModel.name(), e); } }); } @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { try { ValueModel valueModel = ValueModel.acquire(context.getRequiredType()); Object result = valueModel.heapClass().newInstance(); fillInObject(reader, context, valueModel, result); return result; } catch (Exception e) { throw new ConversionException( "class=" + context.getRequiredType().getCanonicalName(), e); } } private void fillInObject(HierarchicalStreamReader reader, UnmarshallingContext context, ValueModel valueModel, Object using) throws ClassNotFoundException { while (reader.hasMoreChildren()) { reader.moveDown(); final String name = reader.getNodeName(); FieldModel fieldModel = valueModel.fields().filter(f -> f.name().equals(name)).findAny().get(); if (fieldModel instanceof ArrayFieldModel) { while (reader.hasMoreChildren()) { reader.moveDown(); try { String index = reader.getNodeName(); int i = Integer.parseInt(index); Method indexedSet = fieldModel.setOrSetOrderedOrSetVolatile(); indexedSet.setAccessible(true); Class<?>[] parameterTypes = indexedSet.getParameterTypes(); Object value = context.convertAnother(null, parameterTypes[1]); indexedSet.invoke(using, i, value); } catch (Exception e) { throw new ConversionException("", e); } reader.moveUp(); } reader.moveUp(); continue; } Method set = fieldModel.setOrSetOrderedOrSetVolatile(); set.setAccessible(true); final Class<?>[] parameterTypes = set.getParameterTypes(); final Object value = context.convertAnother(null, parameterTypes[0]); try { set.invoke(using, value); } catch (Exception e) { throw new ConversionException("", e); } reader.moveUp(); } } @Override public boolean canConvert(Class clazz) { return Values.isValueInterfaceOrImplClass(clazz); } }