Log Message
Merge lambda _expression_ support from trunk.
Modified Paths
- branches/v-1.4.x/pom.xml
- branches/v-1.4.x/xstream/pom.xml
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/XStream.java
- branches/v-1.4.x/xstream-distribution/src/content/changes.html
- branches/v-1.4.x/xstream-distribution/src/content/converters.html
- branches/v-1.4.x/xstream-distribution/src/content/faq.html
Added Paths
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java
- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java
- branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java
Property Changed
Diff
Property changes: branches/v-1.4.x
Modified: svn:mergeinfo
Modified: branches/v-1.4.x/pom.xml (2310 => 2311)
--- branches/v-1.4.x/pom.xml 2015-01-19 00:50:28 UTC (rev 2310)
+++ branches/v-1.4.x/pom.xml 2015-01-28 23:39:47 UTC (rev 2311)
@@ -1,7 +1,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
Copyright (C) 2006 Joe Walnes.
- Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 XStream committers.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015 XStream committers.
All rights reserved.
The software in this package is published under the terms of the BSD
@@ -34,6 +34,16 @@
<profiles>
<profile>
+ <id>jdk19</id>
+ <activation>
+ <jdk>1.9</jdk>
+ </activation>
+ <properties>
+ <version.java.source>1.6</version.java.source>
+ <version.java.target>1.6</version.java.target>
+ </properties>
+ </profile>
+ <profile>
<id>jdk15-ge</id>
<activation>
<jdk>[1.5,)</jdk>
Modified: branches/v-1.4.x/xstream/pom.xml (2310 => 2311)
--- branches/v-1.4.x/xstream/pom.xml 2015-01-19 00:50:28 UTC (rev 2310)
+++ branches/v-1.4.x/xstream/pom.xml 2015-01-28 23:39:47 UTC (rev 2311)
@@ -1,7 +1,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
Copyright (C) 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
@@ -216,6 +216,75 @@
<profiles>
<profile>
+ <id>jdk18ge</id>
+ <activation>
+ <jdk>[1.8,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <compilerArgs>
+ <arg>-XDignore.symbol.file</arg>
+ </compilerArgs>
+ <excludes>
+ <exclude>**/Lambda**</exclude>
+ </excludes>
+ <testExcludes>
+ <exclude>**/Lambda**</exclude>
+ </testExcludes>
+ </configuration>
+ <executions>
+ <execution>
+ <id>compile-jdk18</id>
+ <configuration>
+ <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>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>jdk17</id>
+ <activation>
+ <jdk>1.7</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <compilerArgs>
+ <arg>-XDignore.symbol.file</arg>
+ </compilerArgs>
+ <excludes>
+ <exclude>**/Lambda**</exclude>
+ </excludes>
+ <testExcludes>
+ <exclude>**/Lambda**</exclude>
+ </testExcludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
<id>jdk15-16</id>
<activation>
<jdk>[1.5,1.7)</jdk>
@@ -226,7 +295,14 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
+ <compilerArgs>
+ <arg>-XDignore.symbol.file</arg>
+ </compilerArgs>
+ <excludes>
+ <exclude>**/Lambda**</exclude>
+ </excludes>
<testExcludes>
+ <exclude>**/Lambda**</exclude>
<exclude>**/extended/*17Test*</exclude>
</testExcludes>
</configuration>
@@ -299,16 +375,19 @@
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
+ <exclude>**/Lambda**</exclude>
<exclude>**/annotations/*</exclude>
<exclude>**/AnnotationMapper*</exclude>
<exclude>**/EnumMapper*</exclude>
<exclude>**/enums/*</exclude>
<exclude>**/basic/StringBuilder*</exclude>
<exclude>**/basic/UUID*</exclude>
+ <exclude>**/core/util/Types*</exclude>
<exclude>**/extended/*15*</exclude>
<exclude>**/io/xml/JDom2*</exclude>
</excludes>
<testExcludes>
+ <exclude>**/Lambda**</exclude>
<exclude>**/annotations/*</exclude>
<exclude>**/enums/*</exclude>
<exclude>**/extended/*17Test*</exclude>
Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/XStream.java (2310 => 2311)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/XStream.java 2015-01-19 00:50:28 UTC (rev 2310)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/XStream.java 2015-01-28 23:39:47 UTC (rev 2311)
@@ -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
@@ -599,6 +599,10 @@
}
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);
if (JVM.is15()) {
mapper = buildMapperDynamically(ANNOTATION_MAPPER_TYPE, new Class[]{
@@ -621,6 +625,9 @@
} catch (Exception e) {
throw new com.thoughtworks.xstream.InitializationException(
"Could not instantiate mapper : " + className, e);
+ } catch (LinkageError e) {
+ throw new com.thoughtworks.xstream.InitializationException(
+ "Could not instantiate mapper : " + className, e);
}
}
@@ -756,6 +763,9 @@
alias("string-builder", JVM.loadClassForName("java.lang.StringBuilder"));
alias("uuid", JVM.loadClassForName("java.util.UUID"));
}
+ if (JVM.loadClassForName("java.lang.invoke.SerializedLambda") != null) {
+ aliasDynamically("serialized-lambda", "java.lang.invoke.SerializedLambda");
+ }
}
private void aliasDynamically(String alias, String className) {
@@ -883,6 +893,11 @@
"com.thoughtworks.xstream.converters.basic.UUIDConverter", 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);
@@ -902,6 +917,9 @@
} catch (Exception e) {
throw new com.thoughtworks.xstream.InitializationException(
"Could not instantiate converter : " + className, e);
+ } catch (LinkageError e) {
+ throw new com.thoughtworks.xstream.InitializationException(
+ "Could not instantiate converter : " + className, e);
}
}
Copied: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java (from rev 2310, trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java) (0 => 2311)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java (rev 0)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/LambdaConverter.java 2015-01-28 23:39:47 UTC (rev 2311)
@@ -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);
+ }
+ }
+}
Copied: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java (from rev 2310, trunk/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java) (0 => 2311)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java (rev 0)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/Types.java 2015-01-28 23:39:47 UTC (rev 2311)
@@ -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();
+ }
+
+}
Copied: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java (from rev 2310, trunk/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java) (0 => 2311)
--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java (rev 0)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/mapper/LambdaMapper.java 2015-01-28 23:39:47 UTC (rev 2311)
@@ -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);
+ }
+}
Copied: branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java (from rev 2310, trunk/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java) (0 => 2311)
--- branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java (rev 0)
+++ branches/v-1.4.x/xstream/src/test/com/thoughtworks/acceptance/LambdaTest.java 2015-01-28 23:39:47 UTC (rev 2311)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014, 2015 XStream Committers.
+ * All rights reserved.
+ *
+ * The software in this package is published under the terms of the BSD
+ * style license a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ *
+ * Created on 31. December 2014 by Joerg Schaible
+ */
+package com.thoughtworks.acceptance;
+
+import java.io.Serializable;
+import java.lang.invoke.SerializedLambda;
+import java.util.concurrent.Callable;
+
+
+/**
+ * @author Jörg Schaible
+ */
+public class LambdaTest extends AbstractAcceptanceTest {
+ public static class LambdaKeeper {
+ private Callable<String> callable;
+ @SuppressWarnings("unused")
+ private Object referenced;
+
+ void keep(final Callable<String> c) {
+ callable = c;
+ }
+
+ void reference() {
+ referenced = callable;
+ }
+ }
+
+ public void testLambdaExpression() {
+ 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(new Class[]{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");
+
+ 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(new Class[]{SerializedLambda.class});
+
+ assertBothWaysNormalized(keeper, expected);
+
+ // ... deserialization fails if code was compiled with compiler of different vendor
+ // Object resultRoot = xstream.fromXML(expected);
+ // assertNotNull(resultRoot);
+ }
+
+ public void testReferencedLambdaExpression() {
+ final LambdaKeeper keeper = new LambdaKeeper();
+ keeper.keep((Callable<String> & Serializable)() -> "result");
+ keeper.reference();
+
+ 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(new Class[]{SerializedLambda.class});
+
+ assertBothWaysNormalized(keeper, expected);
+ }
+
+ 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(new Class[]{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));
+
+ final Object resultRoot = xstream.fromXML(resultXml);
+ resultXml = toXML(resultRoot);
+ assertEquals(normalizeLambda(expected), normalizeLambda(resultXml));
+ }
+
+ private String normalizeLambda(final String xml) {
+ // unify compiler specific name for implMethodName, Eclipse uses always "lambda$0"
+ return xml.replaceAll(">lambda\\$[^<]+<", ">lambda\\$0<");
+ }
+}
Modified: branches/v-1.4.x/xstream-distribution/src/content/changes.html (2310 => 2311)
--- branches/v-1.4.x/xstream-distribution/src/content/changes.html 2015-01-19 00:50:28 UTC (rev 2310)
+++ branches/v-1.4.x/xstream-distribution/src/content/changes.html 2015-01-28 23:39:47 UTC (rev 2311)
@@ -32,9 +32,14 @@
<p>Not yet released.</p>
+ <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: branches/v-1.4.x/xstream-distribution/src/content/converters.html (2310 => 2311)
--- branches/v-1.4.x/xstream-distribution/src/content/converters.html 2015-01-19 00:50:28 UTC (rev 2310)
+++ branches/v-1.4.x/xstream-distribution/src/content/converters.html 2015-01-28 23:39:47 UTC (rev 2311)
@@ -1,7 +1,7 @@
<html>
<!--
Copyright (C) 2005, 2006 Joe Walnes.
- Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013 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
@@ -128,7 +128,7 @@
<td>normal</td>
</tr>
<tr>
- <td><a href=""
+ <td><a href=""
<td>any kind of array</td>
<td class="example">
<<i>string</i>-array><br/>
@@ -250,7 +250,7 @@
<td>normal</td>
</tr>
<tr>
- <td><a href=""
+ <td><a href=""
<td>java.util.ArrayList<br/>java.util.LinkedList<br/>java.util.HashSet<br/>java.util.Vector<br/>java.util.LinkedHashSet</td>
<td class="example">
<linked-list><br/>
@@ -264,7 +264,7 @@
<td> </td>
</tr>
<tr>
- <td><a href=""
+ <td><a href=""
<td>java.util.HashMap<br/>java.util.Hashtable<br/>java.util.LinkedHashMap<br/>java.util.concurrent.ConcurrentHashMap</td>
<td class="example">
<map><br/>
@@ -848,6 +848,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: branches/v-1.4.x/xstream-distribution/src/content/faq.html (2310 => 2311)
--- branches/v-1.4.x/xstream-distribution/src/content/faq.html 2015-01-19 00:50:28 UTC (rev 2310)
+++ branches/v-1.4.x/xstream-distribution/src/content/faq.html 2015-01-28 23:39:47 UTC (rev 2311)
@@ -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
@@ -63,6 +63,10 @@
<!-- ...................................................... -->
<h2 id="Compatibility_enhanced_mode_advantage">What are the advantages of using enhanced mode over pure Java mode?</h2>
+ <p>Currently it is not possible to recreate every instance of a type using the official Java API only. The enhanced mode uses some undocumented, but wide-spread
+ available functionality to recreate such instances nevertheless. However, in a secured secured environment, older Java run times or a limited Java environment might
+ prevent the usage of the enhanced mode and XStream uses the plain Java API as fallback. This mode has some restrictions though:</p>
+
<table summary="Comparison of pure Java and enhanced mode">
<tr><th>Feature</th><th>Pure Java</th><th>Enhanced Mode</th></tr>
<tr><td>Public classes</td><td>Yes</td><td>Yes</td></tr>
@@ -200,6 +204,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 +292,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:
