Log Message
Support lambda expressions directly. Fix referenced lambda _expression_ (XSTR-767).
Modified Paths
- trunk/xstream/pom.xml
- trunk/xstream/src/java/com/thoughtworks/xstream/XStream.java
- trunk/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java
- trunk/xstream-distribution/src/content/changes.html
- trunk/xstream-distribution/src/content/converters.html
- trunk/xstream-distribution/src/content/faq.html
Added Paths
Diff
Modified: trunk/xstream/pom.xml (2307 => 2308)
--- trunk/xstream/pom.xml 2015-01-10 23:54:12 UTC (rev 2307)
+++ trunk/xstream/pom.xml 2015-01-19 00:27:54 UTC (rev 2308)
@@ -229,6 +229,9 @@
<compilerArgs>
<arg>-XDignore.symbol.file</arg>
</compilerArgs>
+ <excludes>
+ <exclude>**/Lambda**</exclude>
+ </excludes>
<testExcludes>
<exclude>**/Lambda**</exclude>
</testExcludes>
@@ -237,13 +240,17 @@
<execution>
<id>compile-jdk18</id>
<configuration>
- <source>1.8</source>
- <target>1.8</target>
- <testExcludes>
- <exclude>foo</exclude>
- </testExcludes>
+ <source>1.8</source>
+ <target>1.8</target>
+ <excludes>
+ <exclude>foo</exclude>
+ </excludes>
+ <testExcludes>
+ <exclude>foo</exclude>
+ </testExcludes>
</configuration>
<goals>
+ <goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
@@ -266,6 +273,9 @@
<compilerArgs>
<arg>-XDignore.symbol.file</arg>
</compilerArgs>
+ <excludes>
+ <exclude>**/Lambda**</exclude>
+ </excludes>
<testExcludes>
<exclude>**/Lambda**</exclude>
</testExcludes>
@@ -288,6 +298,9 @@
<compilerArgs>
<arg>-XDignore.symbol.file</arg>
</compilerArgs>
+ <excludes>
+ <exclude>**/Lambda**</exclude>
+ </excludes>
<testExcludes>
<exclude>**/Lambda**</exclude>
<exclude>**/extended/*17Test*</exclude>
Modified: trunk/xstream/src/java/com/thoughtworks/xstream/XStream.java (2307 => 2308)
--- trunk/xstream/src/java/com/thoughtworks/xstream/XStream.java 2015-01-10 23:54:12 UTC (rev 2307)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/XStream.java 2015-01-19 00:27:54 UTC (rev 2308)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2003, 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
@@ -571,6 +571,10 @@
mapper = new EnumMapper(mapper);
mapper = new LocalConversionMapper(mapper);
mapper = new ImmutableTypesMapper(mapper);
+ if (JVM.is18()) {
+ mapper = buildMapperDynamically("com.thoughtworks.xstream.mapper.LambdaMapper", new Class[]{Mapper.class},
+ new Object[]{mapper});
+ }
mapper = new SecurityMapper(mapper);
mapper = new AnnotationMapper(mapper, converterRegistry, converterLookup, classLoaderReference,
reflectionProvider);
@@ -579,7 +583,6 @@
return mapper;
}
- @SuppressWarnings("unused")
private Mapper buildMapperDynamically(final String className, final Class<?>[] constructorParamTypes,
final Object[] constructorParamValues) {
try {
@@ -737,6 +740,9 @@
if (JVM.loadClassForName("javax.xml.datatype.Duration") != null) {
aliasDynamically("duration", "javax.xml.datatype.Duration");
}
+ if (JVM.loadClassForName("java.lang.invoke.SerializedLambda") != null) {
+ aliasDynamically("serialized-lambda", "java.lang.invoke.SerializedLambda");
+ }
}
private void aliasDynamically(final String alias, final String className) {
@@ -832,6 +838,11 @@
registerConverterDynamically("com.thoughtworks.xstream.converters.extended.DurationConverter",
PRIORITY_NORMAL, null, null);
}
+ if (JVM.is18()) {
+ registerConverterDynamically("com.thoughtworks.xstream.converters.reflection.LambdaConverter",
+ PRIORITY_NORMAL, new Class[]{Mapper.class, ReflectionProvider.class, ClassLoaderReference.class},
+ new Object[]{mapper, reflectionProvider, classLoaderReference});
+ }
registerConverter(new SelfStreamingInstanceChecker(converterLookup, this), PRIORITY_NORMAL);
}
Added: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java (0 => 2308)
--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java (rev 0)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java 2015-01-19 00:27:54 UTC (rev 2308)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 XStream Committer.
+ * All rights reserved.
+ *
+ * Created on 17. January 2015 by Joerg Schaible
+ */
+package com.thoughtworks.xstream.converters.reflection;
+
+import java.io.Serializable;
+
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.core.ClassLoaderReference;
+import com.thoughtworks.xstream.core.JVM;
+import com.thoughtworks.xstream.core.util.Types;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+
+/**
+ * Converts a lambda type.
+ *
+ * The implementation maps any non-serializable lambda instance to {@code null}.
+ *
+ * @author Jörg Schaible
+ * @since upcoming
+ */
+public class LambdaConverter extends SerializableConverter {
+
+ /**
+ * Constructs a LambdaConverter.
+ *
+ * @param mapper
+ * @param reflectionProvider
+ * @param classLoaderReference
+ * @since upcoming
+ */
+ public LambdaConverter(
+ final Mapper mapper, final ReflectionProvider reflectionProvider,
+ final ClassLoaderReference classLoaderReference) {
+ super(mapper, reflectionProvider, classLoaderReference);
+ }
+
+ @Override
+ public boolean canConvert(final Class<?> type) {
+ return Types.isLambdaType(type)
+ && (JVM.canCreateDerivedObjectOutputStream() || !Serializable.class.isAssignableFrom(type));
+ }
+
+ @Override
+ public void marshal(final Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) {
+ if (original instanceof Serializable) {
+ super.marshal(original, writer, context);
+ }
+ }
+}
Property changes on: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java
___________________________________________________________________
Added: svn:keywords
Added: svn:eol-style
Added: trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java (0 => 2308)
--- trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java (rev 0)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java 2015-01-19 00:27:54 UTC (rev 2308)
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 XStream Committers.
+ * All rights reserved.
+ *
+ * Created on 17. January 2015 by Joerg Schaible
+ */
+package com.thoughtworks.xstream.core.util;
+
+import java.util.regex.Pattern;
+
+
+/**
+ * Helper methods for class types.
+ *
+ * @author Jörg Schaible
+ * @since upcoming
+ */
+public class Types {
+ private static final Pattern lambdaPattern = Pattern.compile(".*\\$\\$Lambda\\$[0-9]+/.*");
+
+ public static final boolean isLambdaType(final Class<?> type) {
+ return type != null && type.isSynthetic() && lambdaPattern.matcher(type.getSimpleName()).matches();
+ }
+
+}
Property changes on: trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java
___________________________________________________________________
Added: svn:keywords
Added: svn:eol-style
Added: trunk/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java (0 => 2308)
--- trunk/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java (rev 0)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java 2015-01-19 00:27:54 UTC (rev 2308)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 XStream Committers.
+ * All rights reserved.
+ *
+ * Created on 15. January 2015 by Joerg Schaible
+ */
+package com.thoughtworks.xstream.mapper;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import com.thoughtworks.xstream.core.util.Types;
+
+
+/**
+ * Mapper to map serializable lambda types to the name of their functional interface and non-serializable ones to
+ * Mapper.Null.
+ *
+ * @author Jörg Schaible
+ * @since upcoming
+ */
+public class LambdaMapper extends MapperWrapper {
+
+ /**
+ * Constructs a LambdaMapper.
+ *
+ * @param wrapped mapper
+ * @since upcoming
+ */
+ public LambdaMapper(final Mapper wrapped) {
+ super(wrapped);
+ }
+
+ @Override
+ public String serializedClass(final Class<?> type) {
+ Class<?> replacement = null;
+ if (Types.isLambdaType(type)) {
+ if (Serializable.class.isAssignableFrom(type)) {
+ final Class<?>[] interfaces = type.getInterfaces();
+ if (interfaces.length > 1) {
+ for (int i = 0; replacement == null && i < interfaces.length; i++) {
+ final Class<?> iface = interfaces[i];
+ for (final Method method : iface.getMethods()) {
+ if (!method.isDefault() && !Modifier.isStatic(method.getModifiers())) {
+ replacement = iface;
+ break;
+ }
+ }
+ }
+ } else {
+ replacement = interfaces[0];
+ }
+ } else {
+ replacement = Null.class;
+ }
+ }
+ return super.serializedClass(replacement == null ? type : replacement);
+ }
+}
Property changes on: trunk/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java
___________________________________________________________________
Added: svn:keywords
Added: svn:eol-style
Modified: trunk/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java (2307 => 2308)
--- trunk/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java 2015-01-10 23:54:12 UTC (rev 2307)
+++ trunk/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java 2015-01-19 00:27:54 UTC (rev 2308)
@@ -14,107 +14,188 @@
import java.lang.invoke.SerializedLambda;
import java.util.concurrent.Callable;
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.mapper.MapperWrapper;
/**
* @author Jörg Schaible
*/
public class LambdaTest extends AbstractAcceptanceTest {
- String s = "";
-
public static class LambdaKeeper {
private Callable<String> callable;
@SuppressWarnings("unused")
- private Callable<String> referenced;
- void keep(Callable<String> c) {
+ private Object referenced;
+
+ void keep(final Callable<String> c) {
callable = c;
}
+
void reference() {
referenced = callable;
}
}
-
+
public void testLambdaExpression() {
- LambdaKeeper keeper = new LambdaKeeper();
+ final LambdaKeeper keeper = new LambdaKeeper();
+ keeper.keep((Callable<String>)() -> "result");
+
+ final String expected = "" + "<keeper>\n" + " <callable class=\"null\"/>\n" + "</keeper>";
+ xstream.alias("keeper", LambdaKeeper.class);
+ xstream.allowTypes(SerializedLambda.class);
+
+ assertEquals(expected, xstream.toXML(keeper));
+ assertBothWays(xstream.fromXML(expected), "<keeper/>");
+ }
+
+ public void testSerializableLambdaExpression() {
+ final LambdaKeeper keeper = new LambdaKeeper();
keeper.keep((Callable<String> & Serializable)() -> "result");
-
- String expected = ""
- + "<keeper>\n"
- + " <callable class=\"" + keeper.callable.getClass().getName() + "\" resolves-to=\"java.lang.invoke.SerializedLambda\">\n"
- + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
- + " <functionalInterfaceClass>java/util/concurrent/Callable</functionalInterfaceClass>\n"
- + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
- + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
- + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
- + " <implMethodName>lambda$0</implMethodName>\n" // Eclipse compiler name
- + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
- + " <implMethodKind>6</implMethodKind>\n"
- + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
- + " <capturedArgs/>\n"
- + " </callable>\n"
- + "</keeper>";
+
+ final String expected = ""
+ + "<keeper>\n"
+ + " <callable resolves-to=\"serialized-lambda\">\n"
+ + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
+ + " <functionalInterfaceClass>java/util/concurrent/Callable</functionalInterfaceClass>\n"
+ + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
+ + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
+ + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
+ + " <implMethodName>lambda$0</implMethodName>\n"
+ + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
+ + " <implMethodKind>6</implMethodKind>\n"
+ + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
+ + " <capturedArgs/>\n"
+ + " </callable>\n"
+ + "</keeper>";
xstream.alias("keeper", LambdaKeeper.class);
xstream.allowTypes(SerializedLambda.class);
assertBothWaysNormalized(keeper, expected);
-// Object resultRoot = xstream.fromXML(expected);
-// assertNotNull(resultRoot);
+ // ... deserialization fails if code was compiled with compiler of different vendor
+ // Object resultRoot = xstream.fromXML(expected);
+ // assertNotNull(resultRoot);
}
-
+
public void testReferencedLambdaExpression() {
- LambdaKeeper keeper = new LambdaKeeper();
+ final LambdaKeeper keeper = new LambdaKeeper();
keeper.keep((Callable<String> & Serializable)() -> "result");
keeper.reference();
-
- String expected = ""
- + "<keeper>\n"
- + " <callable class=\"" + keeper.callable.getClass().getName() + "\" resolves-to=\"java.lang.invoke.SerializedLambda\">\n"
- + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
- + " <functionalInterfaceClass>java/util/concurrent/Callable</functionalInterfaceClass>\n"
- + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
- + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
- + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
- + " <implMethodName>lambda$0</implMethodName>\n" // Eclipse compiler name
- + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
- + " <implMethodKind>6</implMethodKind>\n"
- + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
- + " <capturedArgs/>\n"
- + " </callable>\n"
- + " <referenced class=\"" +keeper.callable.getClass().getName() + "\" reference=\"../callable\"/>\n"
- + "</keeper>";
- xstream = new XStream() {
- protected MapperWrapper wrapMapper(MapperWrapper next) {
- return new MapperWrapper(next) {
- @Override
- public Class<?> realClass(String elementName) {
- if (elementName.matches(".*\\$\\$Lambda\\$[0-9]+/[0-9]+"))
- return null;
- else
- return super.realClass(elementName);
- }
- };
- }
- };
- setupSecurity(xstream);
+ final String expected = ""
+ + "<keeper>\n"
+ + " <callable resolves-to=\"serialized-lambda\">\n"
+ + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
+ + " <functionalInterfaceClass>java/util/concurrent/Callable</functionalInterfaceClass>\n"
+ + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
+ + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
+ + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
+ + " <implMethodName>lambda$0</implMethodName>\n"
+ + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
+ + " <implMethodKind>6</implMethodKind>\n"
+ + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
+ + " <capturedArgs/>\n"
+ + " </callable>\n"
+ + " <referenced class=\"java.util.concurrent.Callable\" reference=\"../callable\"/>\n"
+ + "</keeper>";
xstream.alias("keeper", LambdaKeeper.class);
xstream.allowTypes(SerializedLambda.class);
assertBothWaysNormalized(keeper, expected);
}
- private void assertBothWaysNormalized(LambdaKeeper keeper, String expected) {
- String resultXml = toXML(keeper);
+ public interface X {
+ static int getTwo() {
+ return 2;
+ }
+
+ default int getOne() {
+ return 1;
+ }
+ }
+
+ public interface SerializableCallable<T> extends X, Serializable, Callable<T> {}
+
+ public void testLambdaArray() {
+ Object[] lambdas = {
+ (Callable<String> & Serializable)() -> "result", (SerializableCallable<String>)() -> "result",
+ (Runnable & Serializable)() -> run(), (X & Serializable & Callable<String>)() -> "result",
+ (Runnable)() -> run(), null};
+ lambdas[lambdas.length - 1] = lambdas[0];
+
+ final String expected = ""
+ + "<object-array>\n"
+ + " <callable resolves-to=\"serialized-lambda\">\n"
+ + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
+ + " <functionalInterfaceClass>java/util/concurrent/Callable</functionalInterfaceClass>\n"
+ + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
+ + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
+ + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
+ + " <implMethodName>lambda$0</implMethodName>\n"
+ + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
+ + " <implMethodKind>6</implMethodKind>\n"
+ + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
+ + " <capturedArgs/>\n"
+ + " </callable>\n"
+ + " <serializable-callable resolves-to=\"serialized-lambda\">\n"
+ + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
+ + " <functionalInterfaceClass>com/thoughtworks/acceptance/LambdaTest$SerializableCallable</functionalInterfaceClass>\n"
+ + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
+ + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
+ + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
+ + " <implMethodName>lambda$0</implMethodName>\n"
+ + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
+ + " <implMethodKind>6</implMethodKind>\n"
+ + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
+ + " <capturedArgs/>\n"
+ + " </serializable-callable>\n"
+ + " <runnable resolves-to=\"serialized-lambda\">\n"
+ + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
+ + " <functionalInterfaceClass>java/lang/Runnable</functionalInterfaceClass>\n"
+ + " <functionalInterfaceMethodName>run</functionalInterfaceMethodName>\n"
+ + " <functionalInterfaceMethodSignature>()V</functionalInterfaceMethodSignature>\n"
+ + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
+ + " <implMethodName>lambda$0</implMethodName>\n"
+ + " <implMethodSignature>()V</implMethodSignature>\n"
+ + " <implMethodKind>7</implMethodKind>\n"
+ + " <instantiatedMethodType>()V</instantiatedMethodType>\n"
+ + " <capturedArgs>\n"
+ + " <com.thoughtworks.acceptance.LambdaTest>\n"
+ + " <fName>testLambdaArray</fName>\n"
+ + " </com.thoughtworks.acceptance.LambdaTest>\n"
+ + " </capturedArgs>\n"
+ + " </runnable>\n"
+ + " <callable resolves-to=\"serialized-lambda\">\n"
+ + " <capturingClass>com.thoughtworks.acceptance.LambdaTest</capturingClass>\n"
+ + " <functionalInterfaceClass>java/util/concurrent/Callable</functionalInterfaceClass>\n"
+ + " <functionalInterfaceMethodName>call</functionalInterfaceMethodName>\n"
+ + " <functionalInterfaceMethodSignature>()Ljava/lang/Object;</functionalInterfaceMethodSignature>\n"
+ + " <implClass>com/thoughtworks/acceptance/LambdaTest</implClass>\n"
+ + " <implMethodName>lambda$0</implMethodName>\n"
+ + " <implMethodSignature>()Ljava/lang/String;</implMethodSignature>\n"
+ + " <implMethodKind>6</implMethodKind>\n"
+ + " <instantiatedMethodType>()Ljava/lang/String;</instantiatedMethodType>\n"
+ + " <capturedArgs/>\n"
+ + " </callable>\n"
+ + " <null/>\n"
+ + " <callable reference=\"../callable\"/>\n"
+ + "</object-array>";
+ xstream.alias("callable", Callable.class);
+ xstream.alias("runnable", Runnable.class);
+ xstream.alias("serializable-callable", SerializableCallable.class);
+ xstream.allowTypes(SerializedLambda.class, LambdaTest.class);
+
+ assertBothWaysNormalized(lambdas, expected);
+ }
+
+ private void assertBothWaysNormalized(final Object original, final String expected) {
+ String resultXml = toXML(original);
assertEquals(normalizeLambda(expected), normalizeLambda(resultXml));
-
- Object resultRoot = xstream.fromXML(resultXml);
+
+ final Object resultRoot = xstream.fromXML(resultXml);
resultXml = toXML(resultRoot);
assertEquals(normalizeLambda(expected), normalizeLambda(resultXml));
}
- private String normalizeLambda(String xml) {
- return xml.replaceAll("\\$\\$Lambda\\$[/0-9]+\"", "\\$\\$Lambda\\$\"").replaceAll(">lambda\\$[^<]+<", ">lambda\\$0<");
+ private String normalizeLambda(final String xml) {
+ // unify compiler specific name for implMethodName, Eclipse uses always "lambda$0"
+ return xml.replaceAll(">lambda\\$[^<]+<", ">lambda\\$0<");
}
}
Modified: trunk/xstream-distribution/src/content/changes.html (2307 => 2308)
--- trunk/xstream-distribution/src/content/changes.html 2015-01-10 23:54:12 UTC (rev 2307)
+++ trunk/xstream-distribution/src/content/changes.html 2015-01-19 00:27:54 UTC (rev 2308)
@@ -57,9 +57,14 @@
<h2>Major changes</h2>
+ <ul>
+ <li>Support for serializable lambda expressions and handling of non-serializable ones.</li>
+ </ul>
+
<h2>Minor changes</h2>
<ul>
+ <li>XSTR-767: Deserialization of referenced lambda expressions fail.</li>
<li>XSTR-762: Private method readResolve() called on base classes.</li>
<li>XSTR-755: ExternalizableConverter does not respect writeReplace and readResolve.</li>
<li>XSTR-757: Deserialized TreeSet does not honor remove(Object) return value contract.</li>
Modified: trunk/xstream-distribution/src/content/converters.html (2307 => 2308)
--- trunk/xstream-distribution/src/content/converters.html 2015-01-10 23:54:12 UTC (rev 2307)
+++ trunk/xstream-distribution/src/content/converters.html 2015-01-19 00:27:54 UTC (rev 2308)
@@ -1,7 +1,7 @@
<html>
<!--
Copyright (C) 2005, 2006 Joe Walnes.
- Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014 XStream committers.
+ Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2014, 2015 XStream committers.
All rights reserved.
The software in this package is published under the terms of the BSD
@@ -826,14 +826,6 @@
<td>very low</td>
</tr>
<tr>
- <td><a href=""
- <td>Any type</td>
- <td>The Converter is used as fallback. It uses reflection to examine the class and will serialize its fields and supports annotations for
- local converters.</td>
- <td>Needs JDK 1.5, default for JDK 1.5. Deprecated since XStream 1.3 and must be registered now explicitly.</td>
- <td> </td>
- </tr>
- <tr>
<td><a href=""
<td>java.io.Serializable or types with one of the serializable methods readObject or writeObject</td>
<td>The Converter is used for any JDK-serializable types, if not handled by a specialized Converter.</td>
@@ -848,6 +840,16 @@
<td>low</td>
</tr>
<tr>
+ <td><a href=""
+ <td>For serializable and non-serializable lambda types. Noon-serialzable lambda instances will be mapped to null, since they
+ contain no information for recreation. Serializable lambda types have such info, but it is specific to compiler vendor and
+ occurrence in the code. Never assume that you can deserialize such an element when you use a different version of your code
+ or a different compiler.</td>
+ <td> </td>
+ <td>Only automatically registered for Java 8.</td>
+ <td>normal</td>
+ </tr>
+ <tr>
<td><a href=""
<td>Any type with all fields to be represented by a single string but one.</td>
<td>The Converter is used to write all but one fields of the type as attributes. The left over field is then used as current value.</td>
Modified: trunk/xstream-distribution/src/content/faq.html (2307 => 2308)
--- trunk/xstream-distribution/src/content/faq.html 2015-01-10 23:54:12 UTC (rev 2307)
+++ trunk/xstream-distribution/src/content/faq.html 2015-01-19 00:27:54 UTC (rev 2308)
@@ -1,7 +1,7 @@
<html>
<!--
Copyright (C) 2005, 2006 Joe Walnes.
- Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 XStream committers.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 XStream committers.
All rights reserved.
The software in this package is published under the terms of the BSD
@@ -200,6 +200,8 @@
<li>Inner class types of the JDK can often vary in implementation details between JDK versions and vendors and are therefore only compatible for the same JDK. This
includes collection types returned by the methods of the Collections class that wrap another one (like unmodifiableList) or the collections that are returned by the
different Map implementations for the keySet(), entrySet() and values() methods.</li>
+ <li><a href="" lambda expressions</a> cannot be deserialized at all and <a href=""
+ lambda</a> _expression_ contain compiler and vendor specific information that might cause deserialization to fail.</li>
</ol>
<!-- ...................................................... -->
@@ -286,13 +288,24 @@
<!-- ...................................................... -->
<h2 id="Serialization_Serializable">Do my classes have to implement Serializable if XStream is to serialize them?</h2>
- <p>No, but XStream respects the Java serialization methods even for types not declared as Serializable.</p>
+ <p>No (except for lambda expressions), but XStream respects the Java serialization methods even for types not declared as Serializable.</p>
<!-- ...................................................... -->
<h2 id="Serialization_proxies">Can dynamic proxies be serialized?</h2>
<p>Yes.</p>
<!-- ...................................................... -->
+ <h2 id="Serialization_lambda_null">My lambda _expression_ is serialized to null!</h2>
+ <p>Non-serializable lambda expressions to not contain any information at all to recreate the instance at a later time again. These instances are treated as temporary
+ objects and as such XStream has no other possibility as to serialize null instead.</p>
+
+ <!-- ...................................................... -->
+ <h2 id="Serialization_lambda_fails">Suddenly the deserialization of my (serializable) lambda _expression_ fails!</h2>
+ <p>Serializable lambda expressions contain information that is specific for compiler and vendor. Even worse, the compiler is free to add information related to the location
+ of the lambda _expression_ in the source i.e. you may not be able to deserialize a lambda _expression_ after source code changes. XStream has no control over this information
+ and how it is used by native functionality in the JDK. Therefore Oracle strongly discourages the usage of serializable lambda expressions in the JDK documentation.</p>
+
+ <!-- ...................................................... -->
<h2 id="Serialization_CGLIB">Can CGLIB proxies be serialized?</h2>
<p>Only limitedly. A proxy generated with the CGLIB Enhancer is supported, if the proxy uses either a factory or
only one callback. Then it is possible to recreate the proxy instance at unmarshalling time. Starting with XStream 1.3.1
To unsubscribe from this list please visit:
