mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
HCOLL-268 refactored the JSON convertor
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
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.lang.model.DataValueClasses;
|
||||
import net.openhft.lang.model.constraints.NotNull;
|
||||
import net.openhft.lang.values.StringValue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.beans.Introspector.getBeanInfo;
|
||||
|
||||
/**
|
||||
* @author Rob Austin.
|
||||
*/
|
||||
public class ChronicleMapConvector<K, V> implements Converter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VanillaChronicleMap.class);
|
||||
|
||||
private final Class entrySetClass;
|
||||
private final Class writeThroughEntryClass;
|
||||
private final Map<K, V> map;
|
||||
|
||||
public ChronicleMapConvector(@NotNull Map map) {
|
||||
|
||||
final String vanillaChronicleMap = VanillaChronicleMap.class.getCanonicalName();
|
||||
|
||||
try {
|
||||
this.entrySetClass = Class.forName(vanillaChronicleMap + "$EntrySet");
|
||||
this.writeThroughEntryClass = Class.forName(vanillaChronicleMap + "$WriteThroughEntry");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConversionException("", e);
|
||||
}
|
||||
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canConvert(Class aClass) {
|
||||
|
||||
if (entrySetClass.isAssignableFrom(aClass) ||
|
||||
writeThroughEntryClass.isAssignableFrom(aClass))
|
||||
return true;
|
||||
|
||||
String canonicalName = aClass.getCanonicalName();
|
||||
|
||||
return canonicalName.startsWith("net.openhft.lang.values") ||
|
||||
canonicalName.endsWith("$$Native") ||
|
||||
canonicalName.endsWith("$$Heap");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext
|
||||
marshallingContext) {
|
||||
|
||||
if (writeThroughEntryClass.isAssignableFrom(o.getClass())) {
|
||||
|
||||
final AbstractMap.SimpleEntry e = (AbstractMap.SimpleEntry) o;
|
||||
Object key = e.getKey();
|
||||
writer.startNode(key.getClass().getCanonicalName());
|
||||
|
||||
|
||||
marshallingContext.convertAnother(key);
|
||||
writer.endNode();
|
||||
|
||||
Object value = e.getValue();
|
||||
writer.startNode(value.getClass().getCanonicalName());
|
||||
|
||||
|
||||
marshallingContext.convertAnother(value);
|
||||
writer.endNode();
|
||||
|
||||
} else if (entrySetClass.isAssignableFrom(o.getClass())) {
|
||||
|
||||
for (Map.Entry e : (Iterable<Map.Entry>) o) {
|
||||
writer.startNode("entry");
|
||||
marshallingContext.convertAnother(e);
|
||||
writer.endNode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final String canonicalName = o.getClass().getCanonicalName();
|
||||
|
||||
boolean isNative = canonicalName.endsWith("$$Native");
|
||||
boolean isHeap = canonicalName.endsWith("$$Heap");
|
||||
|
||||
if (isNative || isHeap) {
|
||||
if (canonicalName.startsWith("net.openhft.lang.values")) {
|
||||
|
||||
Method[] methods = o.getClass().getMethods();
|
||||
|
||||
for (Method method : methods) {
|
||||
|
||||
if (!method.getName().equals("getValue") ||
|
||||
method.getParameterTypes().length != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
marshallingContext.convertAnother(method.invoke(o));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException("class=" + canonicalName, e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ConversionException("class=" + canonicalName);
|
||||
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
|
||||
final BeanInfo info = getBeanInfo(o.getClass()); // new BeanGenerator
|
||||
|
||||
for (PropertyDescriptor p : info.getPropertyDescriptors()) {
|
||||
|
||||
if (p.getName().equals("Class") ||
|
||||
p.getReadMethod() == null ||
|
||||
p.getWriteMethod() == null)
|
||||
continue;
|
||||
|
||||
try {
|
||||
|
||||
final Method readMethod = p.getReadMethod();
|
||||
final Object value = readMethod.invoke(o);
|
||||
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
writer.startNode(p.getDisplayName());
|
||||
marshallingContext.convertAnother(value);
|
||||
writer.endNode();
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("class=" + p.getName(), e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (IntrospectionException e) {
|
||||
throw new ConversionException("class=" + canonicalName, e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader,
|
||||
UnmarshallingContext context) {
|
||||
|
||||
|
||||
if ("cmap".equals(reader.getNodeName())) {
|
||||
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
final String nodeName0 = reader.getNodeName();
|
||||
|
||||
if (!nodeName0.equals("entry"))
|
||||
throw new ConversionException("unable to convert node " +
|
||||
"named=" + nodeName0);
|
||||
final K k;
|
||||
final V v;
|
||||
|
||||
reader.moveDown();
|
||||
k = (K) deserialize(context, reader);
|
||||
reader.moveUp();
|
||||
|
||||
reader.moveDown();
|
||||
v = (V) deserialize(context, reader);
|
||||
reader.moveUp();
|
||||
|
||||
|
||||
if (k != null)
|
||||
map.put(k, v);
|
||||
|
||||
reader.moveUp();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
final String canonicalName = context.getRequiredType().getCanonicalName();
|
||||
|
||||
boolean isNative = canonicalName.endsWith("$$Native");
|
||||
boolean isHeap = canonicalName.endsWith("$$Heap");
|
||||
|
||||
if (!isNative && !isHeap)
|
||||
return null;
|
||||
|
||||
if (context.getRequiredType().getCanonicalName().startsWith
|
||||
("net.openhft.lang.values"))
|
||||
return toNativeValueObjects(reader, context.getRequiredType());
|
||||
|
||||
final String nodeName = isNative ?
|
||||
|
||||
canonicalName.substring(0, canonicalName.length() -
|
||||
"$$Native".length()) :
|
||||
|
||||
canonicalName.substring(0, canonicalName.length() -
|
||||
"$$Heap".length());
|
||||
|
||||
try {
|
||||
|
||||
final Class<?> interfaceClass = Class.forName(nodeName);
|
||||
|
||||
final Object result = (isNative) ?
|
||||
DataValueClasses.newDirectInstance(interfaceClass) :
|
||||
DataValueClasses.newInstance(interfaceClass);
|
||||
|
||||
final BeanInfo beanInfo = getBeanInfo(result.getClass());
|
||||
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
|
||||
final String name = reader.getNodeName();
|
||||
|
||||
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
|
||||
|
||||
if (!descriptor.getName().equals(name))
|
||||
continue;
|
||||
|
||||
final Class<?>[] parameterTypes = descriptor.getWriteMethod()
|
||||
.getParameterTypes();
|
||||
|
||||
if (parameterTypes.length != 1)
|
||||
continue;
|
||||
|
||||
final Object object = context.convertAnother(null, parameterTypes[0]);
|
||||
|
||||
try {
|
||||
descriptor.getWriteMethod().invoke(result, object);
|
||||
} catch (Exception e) {
|
||||
LOG.error("", e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
reader.moveUp();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException("class=" + canonicalName, e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static Object deserialize(@NotNull UnmarshallingContext unmarshallingContext,
|
||||
@NotNull HierarchicalStreamReader reader) {
|
||||
|
||||
final String clazz = reader.getNodeName();
|
||||
|
||||
switch (clazz) {
|
||||
|
||||
case "java.util.Collections$EmptySet":
|
||||
return Collections.EMPTY_SET;
|
||||
|
||||
case "java.util.Collections$EmptyList":
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
case "java.util.Collections$EmptyMap":
|
||||
case "java.util.Collections.EmptyMap":
|
||||
return Collections.EMPTY_MAP;
|
||||
|
||||
}
|
||||
|
||||
return unmarshallingContext.convertAnother(null, forName(clazz));
|
||||
}
|
||||
|
||||
static Class forName(String clazz) {
|
||||
|
||||
try {
|
||||
|
||||
return Class.forName(clazz);
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
boolean isNative = clazz.endsWith("$$Native");
|
||||
boolean isHeap = clazz.endsWith("$$Heap");
|
||||
|
||||
if (!isNative && !isHeap)
|
||||
throw new ConversionException("class=" + clazz, e);
|
||||
|
||||
final String nativeInterface = isNative ? clazz.substring(0, clazz.length() -
|
||||
"$$Native".length()) : clazz.substring(0, clazz.length() -
|
||||
"$$Heap".length());
|
||||
try {
|
||||
DataValueClasses.newDirectInstance(Class.forName(clazz));
|
||||
return Class.forName(nativeInterface);
|
||||
} catch (Exception e1) {
|
||||
throw new ConversionException("class=" + clazz, e1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Object toNativeValueObjects(HierarchicalStreamReader reader, final Class aClass) {
|
||||
|
||||
final Object o = DataValueClasses.newDirectInstance(aClass);
|
||||
|
||||
try {
|
||||
|
||||
final BeanInfo info = Introspector.getBeanInfo(o.getClass()); // new BeanGenerator
|
||||
|
||||
for (PropertyDescriptor p : info.getPropertyDescriptors()) {
|
||||
|
||||
if (!p.getName().equals("value")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String value = reader.getValue();
|
||||
Class<?> parameterType = p.getPropertyType();
|
||||
|
||||
if (StringValue.class.isAssignableFrom(o.getClass())) {
|
||||
((StringValue) o).setValue(value);
|
||||
return o;
|
||||
}
|
||||
|
||||
if (parameterType.isPrimitive()) {
|
||||
|
||||
// convert the primitive to their boxed type
|
||||
|
||||
if (parameterType == int.class)
|
||||
parameterType = Integer.class;
|
||||
else if (parameterType == char.class)
|
||||
parameterType = Character.class;
|
||||
else {
|
||||
final String name = parameterType.getSimpleName();
|
||||
|
||||
final String properName = "java.lang." + Character.toString
|
||||
(name.charAt(0)).toUpperCase()
|
||||
+ name.substring(1);
|
||||
parameterType = Class.forName(properName);
|
||||
}
|
||||
}
|
||||
|
||||
final Method valueOf = parameterType.getMethod("valueOf", String.class);
|
||||
final Object boxedValue = valueOf.invoke(null, value);
|
||||
|
||||
p.getWriteMethod().invoke(o, boxedValue);
|
||||
return o;
|
||||
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
|
||||
throw new ConversionException("setValue(..) method not found in class=" +
|
||||
aClass.getCanonicalName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,12 +19,6 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
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 com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
|
||||
import net.openhft.chronicle.hash.ChronicleHashErrorListener;
|
||||
import net.openhft.chronicle.hash.hashing.Hasher;
|
||||
@@ -47,13 +41,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -61,13 +50,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import static java.beans.Introspector.getBeanInfo;
|
||||
import static java.lang.Long.numberOfTrailingZeros;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Thread.currentThread;
|
||||
import static java.nio.ByteBuffer.allocateDirect;
|
||||
import static net.openhft.chronicle.map.Asserts.assertNotNull;
|
||||
import static net.openhft.chronicle.map.XStreamHelper.deserialize;
|
||||
import static net.openhft.lang.MemoryUnit.*;
|
||||
|
||||
class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
@@ -673,7 +659,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
final XStream xstream = new XStream(new JettisonMappedXmlDriver());
|
||||
xstream.setMode(XStream.NO_REFERENCES);
|
||||
xstream.alias("cmap", VanillaChronicleMap.EntrySet.class);
|
||||
lazyXStreamConverter().registerConverter(xstream);
|
||||
xstream.registerConverter(new ChronicleMapConvector(this));
|
||||
|
||||
OutputStream outputStream = new FileOutputStream(toFile);
|
||||
if (toFile.getName().toLowerCase().endsWith(".gz"))
|
||||
@@ -688,9 +674,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
final XStream xstream = new XStream(new JettisonMappedXmlDriver());
|
||||
xstream.setMode(XStream.NO_REFERENCES);
|
||||
xstream.alias("cmap", VanillaChronicleMap.EntrySet.class);
|
||||
|
||||
// ideally we will use java serialization if we can
|
||||
lazyXStreamConverter().registerConverter(xstream);
|
||||
xstream.registerConverter(new ChronicleMapConvector(this));
|
||||
|
||||
InputStream inputStream = new FileInputStream(fromFile);
|
||||
if (fromFile.getName().toLowerCase().endsWith(".gz"))
|
||||
@@ -757,248 +741,6 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, ? super KI>,
|
||||
}
|
||||
}
|
||||
|
||||
private transient XStreamConverter xStreamConverter;
|
||||
|
||||
|
||||
/**
|
||||
* @return a lazily created XStreamConverter
|
||||
*/
|
||||
private XStreamConverter lazyXStreamConverter() {
|
||||
return xStreamConverter != null ? xStreamConverter :
|
||||
(xStreamConverter = new XStreamConverter());
|
||||
}
|
||||
|
||||
private class XStreamConverter {
|
||||
private Bytes buffer;
|
||||
|
||||
public XStreamConverter() {
|
||||
this.buffer = new ByteBufferBytes(allocateDirect((int) entrySize)
|
||||
.order(ByteOrder.nativeOrder()));
|
||||
}
|
||||
|
||||
private void registerConverter(XStream xstream) {
|
||||
final Converter converter = new Converter() {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canConvert(Class aClass) {
|
||||
|
||||
if (EntrySet.class.isAssignableFrom(aClass)
|
||||
|| WriteThroughEntry.class.isAssignableFrom(aClass))
|
||||
return true;
|
||||
|
||||
String canonicalName = aClass.getCanonicalName();
|
||||
|
||||
return canonicalName.startsWith("net.openhft.lang.values")
|
||||
|| canonicalName.endsWith("$$Native") || canonicalName.endsWith
|
||||
("$$Heap");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext
|
||||
marshallingContext) {
|
||||
if (WriteThroughEntry.class.isAssignableFrom(o.getClass())) {
|
||||
|
||||
final SimpleEntry e = (SimpleEntry) o;
|
||||
Object key = e.getKey();
|
||||
writer.startNode(key.getClass().getCanonicalName());
|
||||
|
||||
|
||||
marshallingContext.convertAnother(key);
|
||||
writer.endNode();
|
||||
|
||||
Object value = e.getValue();
|
||||
writer.startNode(value.getClass().getCanonicalName());
|
||||
|
||||
|
||||
marshallingContext.convertAnother(value);
|
||||
writer.endNode();
|
||||
|
||||
} else if (EntrySet.class
|
||||
.isAssignableFrom(o.getClass())) {
|
||||
for (Entry e : (EntrySet) o) {
|
||||
writer.startNode("entry");
|
||||
marshallingContext.convertAnother(e);
|
||||
writer.endNode();
|
||||
}
|
||||
}
|
||||
|
||||
final String canonicalName = o.getClass().getCanonicalName();
|
||||
|
||||
if (canonicalName.startsWith("net.openhft.lang.values")
|
||||
&& (canonicalName.endsWith("$$Native") ||
|
||||
canonicalName.endsWith("$$Heap"))) {
|
||||
|
||||
Method[] methods = o.getClass().getMethods();
|
||||
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equals("getValue") &&
|
||||
method.getParameterTypes().length == 0) {
|
||||
try {
|
||||
marshallingContext.convertAnother(method.invoke(o));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("class=" + canonicalName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (canonicalName.endsWith("$$Native") ||
|
||||
canonicalName.endsWith("$$Heap")) {
|
||||
|
||||
try {
|
||||
BeanInfo info = getBeanInfo(o.getClass()); // new BeanGenerator
|
||||
|
||||
for (PropertyDescriptor p : info.getPropertyDescriptors()) {
|
||||
|
||||
if (p.getName().equals("Class")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p.getReadMethod() != null && p.getWriteMethod() != null) {
|
||||
|
||||
try {
|
||||
|
||||
final Method readMethod = p.getReadMethod();
|
||||
|
||||
Object value = readMethod.invoke(o);
|
||||
if (value != null) {
|
||||
writer.startNode(p.getDisplayName());
|
||||
marshallingContext.convertAnother(value);
|
||||
writer.endNode();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("class=" + p.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (IntrospectionException e) {
|
||||
throw new RuntimeException("class=" + canonicalName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader,
|
||||
UnmarshallingContext unmarshallingContext) {
|
||||
|
||||
String canonicalName = unmarshallingContext.getRequiredType().getCanonicalName();
|
||||
|
||||
boolean isNative = canonicalName.endsWith("$$Native");
|
||||
boolean isHeap = canonicalName.endsWith("$$Heap");
|
||||
|
||||
if (isNative || isHeap) {
|
||||
|
||||
|
||||
if (unmarshallingContext.getRequiredType().getCanonicalName().startsWith
|
||||
("net.openhft.lang.values"))
|
||||
return XStreamHelper.toBuiltIn$$(reader, unmarshallingContext.getRequiredType()
|
||||
);
|
||||
|
||||
|
||||
final String nodeName = isNative ?
|
||||
canonicalName.substring(0, canonicalName.length() -
|
||||
"$$Native".length()) :
|
||||
|
||||
canonicalName.substring(0, canonicalName.length() -
|
||||
"$$Heap".length());
|
||||
|
||||
Object o;
|
||||
|
||||
|
||||
try {
|
||||
Class<?> interfaceClass = Class.forName(nodeName);
|
||||
o = (isNative) ?
|
||||
DataValueClasses.newDirectInstance(interfaceClass) :
|
||||
DataValueClasses.newInstance(interfaceClass);
|
||||
|
||||
final BeanInfo beanInfo = getBeanInfo(o.getClass());
|
||||
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
String name = reader.getNodeName();
|
||||
|
||||
for (PropertyDescriptor methodDescriptor : beanInfo.getPropertyDescriptors()) {
|
||||
if (methodDescriptor.getName().equals(name)) {
|
||||
Class<?>[] parameterTypes = methodDescriptor.getWriteMethod().getParameterTypes();
|
||||
|
||||
if (parameterTypes.length == 1) {
|
||||
Object o1 = unmarshallingContext.convertAnother(null, parameterTypes[0]);
|
||||
try {
|
||||
methodDescriptor.getWriteMethod().invoke(o, o1);
|
||||
} catch (Exception e) {
|
||||
LOG.error("", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
reader.moveUp();
|
||||
}
|
||||
return o;
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException("class=" + canonicalName, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
final String nodeName = reader.getNodeName();
|
||||
|
||||
switch (nodeName) {
|
||||
case "cmap":
|
||||
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
final String nodeName0 = reader.getNodeName();
|
||||
|
||||
if (!nodeName0.equals("entry"))
|
||||
throw new ConversionException("unable to convert node " +
|
||||
"named=" + nodeName0);
|
||||
final K k;
|
||||
final V v;
|
||||
|
||||
|
||||
reader.moveDown();
|
||||
{
|
||||
k = (K) deserialize(unmarshallingContext, reader);
|
||||
}
|
||||
reader.moveUp();
|
||||
reader.moveDown();
|
||||
{
|
||||
v = (V) deserialize(unmarshallingContext, reader);
|
||||
}
|
||||
reader.moveUp();
|
||||
|
||||
|
||||
if (k != null)
|
||||
VanillaChronicleMap.this.put(k, v);
|
||||
|
||||
reader.moveUp();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
xstream.registerConverter(converter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import com.thoughtworks.xstream.converters.ConversionException;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import net.openhft.lang.model.DataValueClasses;
|
||||
import net.openhft.lang.values.StringValue;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Created by Rob on 18/12/14.
|
||||
*/
|
||||
class XStreamHelper {
|
||||
|
||||
|
||||
static Object deserialize(UnmarshallingContext unmarshallingContext, HierarchicalStreamReader
|
||||
reader) {
|
||||
String type = reader.getNodeName();
|
||||
|
||||
switch (type) {
|
||||
|
||||
case "java.util.Collections$EmptySet":
|
||||
return Collections.EMPTY_SET;
|
||||
|
||||
case "java.util.Collections$EmptyList":
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
case "java.util.Collections$EmptyMap":
|
||||
case "java.util.Collections.EmptyMap":
|
||||
return Collections.EMPTY_MAP;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Class o = XStreamHelper.forName(type);
|
||||
return unmarshallingContext.convertAnother(null, o);
|
||||
}
|
||||
|
||||
static Class forName(String type) {
|
||||
|
||||
|
||||
boolean isNative = type.endsWith("$$Native");
|
||||
if (!isNative && !type.endsWith("$$Heap")) {
|
||||
try {
|
||||
return Class.forName(type);
|
||||
} catch (ClassNotFoundException e1) {
|
||||
throw new ConversionException(e1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
return Class.forName(type);
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
String clazz = isNative ? type.substring(0, type.length() -
|
||||
"$$Native".length()) : type.substring(0, type.length() -
|
||||
"$$Heap".length());
|
||||
try {
|
||||
DataValueClasses.newDirectInstance(Class.forName(clazz));
|
||||
} catch (ClassNotFoundException e1) {
|
||||
throw new ConversionException(e1);
|
||||
}
|
||||
try {
|
||||
return Class.forName(type);
|
||||
} catch (ClassNotFoundException e1) {
|
||||
throw new ConversionException(e1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static Object toBuiltIn$$(HierarchicalStreamReader reader, final Class aClass) {
|
||||
|
||||
|
||||
final Object o = DataValueClasses.newDirectInstance(aClass);
|
||||
|
||||
try {
|
||||
|
||||
final BeanInfo info = Introspector.getBeanInfo(o.getClass()); // new BeanGenerator
|
||||
|
||||
for (PropertyDescriptor p : info.getPropertyDescriptors()) {
|
||||
|
||||
if (p.getName().equals("value")) {
|
||||
|
||||
final String value = reader.getValue();
|
||||
Class<?> parameterType = p.getPropertyType();
|
||||
|
||||
|
||||
if (StringValue.class.isAssignableFrom(o.getClass())) {
|
||||
((StringValue) o).setValue(value);
|
||||
return o;
|
||||
}
|
||||
|
||||
if (parameterType.isPrimitive()) {
|
||||
|
||||
// convert the primitive to their boxed type
|
||||
|
||||
if (parameterType == int.class)
|
||||
parameterType = Integer.class;
|
||||
else if (parameterType == char.class)
|
||||
parameterType = Character.class;
|
||||
else {
|
||||
final String name = parameterType.getSimpleName();
|
||||
|
||||
final String properName = "java.lang." + Character.toString
|
||||
(name.charAt(0)).toUpperCase()
|
||||
+ name.substring(1);
|
||||
parameterType = Class.forName(properName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final Method valueOf = parameterType.getMethod("valueOf", String.class);
|
||||
final Object boxedValue = valueOf.invoke(null, value);
|
||||
|
||||
p.getWriteMethod().invoke(o, boxedValue);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
|
||||
throw new ConversionException("setValue(..) method not found in class=" + aClass
|
||||
.getCanonicalName());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2383,7 +2383,6 @@ public class CHMUseCasesTest {
|
||||
}
|
||||
}
|
||||
|
||||
// @Ignore("HCOLL-268 JSON serialisation issue")
|
||||
@Test
|
||||
public void testMapStringIntegerValueWithoutListMarshallers() throws IOException {
|
||||
ChronicleMapBuilder<String, Map<String, Integer>> builder = ChronicleMapBuilder
|
||||
|
||||
Reference in New Issue
Block a user