@Override public ObjectInputFilter.Status checkInput(FilterInfo filter) { count++; if (filter.serialClass() != null) { if (filter.serialClass().getName().contains("$$Lambda$")) { // TBD: proper identification of serialized Lambdas? // Fold the serialized Lambda into the SerializedLambda type classes.add(SerializedLambda.class); } else if (Proxy.isProxyClass(filter.serialClass())) { classes.add(Proxy.class); } else { classes.add(filter.serialClass()); } } this.maxArray = Math.max(this.maxArray, filter.arrayLength()); this.maxRefs = Math.max(this.maxRefs, filter.references()); this.maxDepth = Math.max(this.maxDepth, filter.depth()); this.maxBytes = Math.max(this.maxBytes, filter.streamBytes()); return ObjectInputFilter.Status.UNDECIDED; }
@Override public ObjectInputFilter.Status checkInput(FilterInfo filter) { Class<?> serialClass = filter.serialClass(); System.out.printf(" checkInput: class: %s, arrayLen: %d, refs: %d, depth: %d, bytes; %d%n", serialClass, filter.arrayLength(), filter.references(), filter.depth(), filter.streamBytes()); count++; if (serialClass != null) { if (serialClass.getName().contains("$$Lambda$")) { // TBD: proper identification of serialized Lambdas? // Fold the serialized Lambda into the SerializedLambda type classes.add(SerializedLambda.class); } else if (Proxy.isProxyClass(serialClass)) { classes.add(Proxy.class); } else { classes.add(serialClass); } } this.maxArray = Math.max(this.maxArray, filter.arrayLength()); this.maxRefs = Math.max(this.maxRefs, filter.references()); this.maxDepth = Math.max(this.maxDepth, filter.depth()); this.maxBytes = Math.max(this.maxBytes, filter.streamBytes()); return ObjectInputFilter.Status.UNDECIDED; }
@SuppressWarnings({ "rawtypes", "unchecked" }) private SerializedValue createLambdaObject(Type type, Object object) { SerializedValue serializedObject = serialized.get(object); if (serializedObject == null) { SerializedLambda serializedLambda = Lambdas.serializeLambda(object); try { Class<?> functionalInterfaceType = classFrom(serializedLambda.getFunctionalInterfaceClass()); Serializer serializer = fetchSerializer(serializedLambda.getClass()); serializedObject = serializer.generate(type, functionalInterfaceType); serialized.put(object, serializedObject); if (serializedObject instanceof SerializedReferenceType) { ((SerializedReferenceType) serializedObject).setId(identityHashCode(object)); } serializer.populate(serializedObject, serializedLambda); } catch (RuntimeException e) { throw new SerializationException(e); } } return serializedObject; }
private Serializer<?> fetchSerializer(Class<?> clazz) { Serializer<?> serializer = serializers.get(clazz); if (serializer != null) { return serializer; } if (clazz.isArray()) { serializer = new ArraySerializer(this); } else if (clazz.isEnum() || (clazz.getSuperclass() != null && clazz.getSuperclass().isEnum())) { serializer = new EnumSerializer(this); } else if (SerializedLambda.class == clazz) { serializer = new LambdaSerializer(this); } else { serializer = new GenericSerializer(this); } return serializer; }
@Override public void populate(SerializedLambdaObject serializedLambda, Object object) { if (!(object instanceof SerializedLambda)) { return; } SerializedLambda lambda = (SerializedLambda) object; serializedLambda.setSignature(new LambdaSignature() .withCapturingClass(lambda.getCapturingClass()) .withInstantiatedMethodType(lambda.getInstantiatedMethodType()) .withFunctionalInterface( lambda.getFunctionalInterfaceClass(), lambda.getFunctionalInterfaceMethodName(), lambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(lambda.getImplClass(), lambda.getImplMethodKind(), lambda.getImplMethodName(), lambda.getImplMethodSignature())); List<SerializedValue> arguments = IntStream.range(0, lambda.getCapturedArgCount()) .mapToObj(lambda::getCapturedArg) .map(o -> facade.serialize(o.getClass(), o)) .collect(toList()); serializedLambda.setCapturedArguments(arguments); }
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(SerializedLambda.class); assertBothWaysNormalized(keeper, expected); }
default SerializedLambda serialized() { try { Method replaceMethod = getClass().getDeclaredMethod("writeReplace"); replaceMethod.setAccessible(true); return (SerializedLambda) replaceMethod.invoke(this); } catch (Exception e) { throw new RuntimeException(e); } }
default Method method() { SerializedLambda lambda = serialized(); Class<?> containingClass = getContainingClass(); return Arrays.asList(containingClass.getDeclaredMethods()) .stream() .filter(method -> Objects.equals(method.getName(), lambda.getImplMethodName())) .findFirst() .orElseThrow(UnableToGuessMethodException::new); }
private static String nameOf(PropertyToMatch<?, ?> property) { Optional<String> propertyName = Stream.<Class<?>>iterate(property.getClass(), Class::getSuperclass) .flatMap(c -> Arrays.stream(c.getDeclaredMethods())) .filter(m -> m.getName().equals("writeReplace")) .map(m -> (SerializedLambda) invoke(m, property)) .map(SerializedLambda::getImplMethodName) .findFirst(); return propertyName.orElseThrow(() -> new RuntimeException("Unable to determine property name.")); }
public LambdaInfo(Object lambda, Kind kind, SerializedLambda serializedLambda, Method functionalMethod, Method implementationMethod) { this.lambda = lambda; this.kind = kind; this.serializedLambda = serializedLambda; this.functionalMethod = functionalMethod; this.implementationMethod = implementationMethod; }
public static String fnToFieldName(Fn fn) { try { Method method = fn.getClass().getDeclaredMethod("writeReplace"); method.setAccessible(Boolean.TRUE); SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn); String getter = serializedLambda.getImplMethodName(); String fieldName = Introspector.decapitalize(getter.replace("get", "")); return fieldName; } catch (ReflectiveOperationException e) { throw new ReflectionOperationException(e); } }
private void assertDeserializeMethod(Class<?> clazz, boolean expectedPresent) { try { Method m = clazz.getDeclaredMethod("$deserializeLambda$", SerializedLambda.class); if (!expectedPresent) fail("Unexpected $deserializeLambda$ in " + clazz); } catch (NoSuchMethodException e) { if (expectedPresent) fail("Expected to find $deserializeLambda$ in " + clazz); } }
private void saveGame() { xstream.autodetectAnnotations(true); xstream.allowTypes(new Class[] {SerializedLambda.class}); spritesCopy = new ArrayList<>(); for (Sprite sprite : spriteModel.getSprites()) { spritesCopy.add(sprite.clone()); } savedSpritesXML = xstream.toXML(spritesCopy); }
public <T> IsPojo<A> where( final MethodReference<A, T> methodReference, final Matcher<T> returnValueMatcher) { final SerializedLambda serializedLambda = serializeLambda(methodReference); ensureDirectMethodReference(serializedLambda); return where( serializedLambda.getImplMethodName(), methodReference, returnValueMatcher); }
private static void ensureDirectMethodReference(final SerializedLambda serializedLambda) { final Method targetMethod; try { final Class<?> implClass = Class.forName(serializedLambda.getImplClass().replace('/', '.')); targetMethod = findMethodByName(implClass, serializedLambda.getImplMethodName()); } catch (NoSuchMethodException | ClassNotFoundException e) { throw new IllegalStateException( "serializeLambda returned a SerializedLambda pointing to an invalid class/method", e); } if (targetMethod.isSynthetic()) { throw new IllegalArgumentException("The supplied lambda is not a direct method reference"); } }
default SerializedLambda serialized() { try { Method replaceMethod = getClass().getDeclaredMethod("writeReplace"); replaceMethod.setAccessible(true); return (SerializedLambda) replaceMethod.invoke(this); } catch (Exception ex) { throw new RuntimeException(ex); } }
default Method method() { SerializedLambda lambda = serialized(); Class<?> containingClass = getContainingClass(); return stream(containingClass.getDeclaredMethods()) .filter(method -> Objects.equals(method.getName(), lambda.getImplMethodName())) .findFirst() .orElseThrow(UnableToGuessMethodException::new); }
private static String[] getSerializedLambdaParameterizedTypeNames(Object source) { Method method = ReflectionUtils.findMethod(source.getClass(), "writeReplace"); if (method == null) { return null; } ReflectionUtils.makeAccessible(method); SerializedLambda serializedLambda = (SerializedLambda) ReflectionUtils .invokeMethod(method, source); String signature = serializedLambda.getImplMethodSignature().replaceAll("[()]",""); List<String> typeNames = Stream.of(signature.split(";")) .map(t -> t.substring(1).replace('/', '.')).collect(Collectors.toList()); return typeNames.toArray(new String[typeNames.size()]); }
@Override public boolean matches(Object item) { if (!Lambdas.isSerializableLambda(item.getClass())) { return false; } SerializedLambda lambda = Lambdas.serializeLambda(item); return lambda.getImplMethodName().equals(name); }
public static SerializedLambda serializeLambda(Object object) { try { Method writeReplace = object.getClass().getDeclaredMethod("writeReplace"); return Reflections.accessing(writeReplace).call(m -> (SerializedLambda) m.invoke(object)); } catch (ReflectiveOperationException e) { return null; } }
@SuppressWarnings("unchecked") @Test public void testSerializeStaticNonCapturing() throws Exception { SerializedLambda serializedLambda = Lambdas.serializeLambda(splus); assertThat(serializedLambda.getCapturedArgCount(), equalTo(0)); LambdaSignature lambda = new LambdaSignature() .withCapturingClass(serializedLambda.getCapturingClass()) .withInstantiatedMethodType(serializedLambda.getInstantiatedMethodType()) .withFunctionalInterface(serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(serializedLambda.getImplClass(), serializedLambda.getImplMethodKind(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); assertThat(lambda.getCapturingClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getFunctionalInterfaceClass(), equalTo("java/util/function/BiFunction")); assertThat(lambda.getFunctionalInterfaceMethod().getDeclaringClass(), equalTo(BiFunction.class)); assertThat(lambda.getFunctionalInterfaceMethodName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethodSignature(), equalTo("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")); assertThat(lambda.getFunctionalInterfaceMethod().getName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethod().getParameterTypes(), arrayContaining(Object.class, Object.class)); assertThat(lambda.getImplClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getImplMethod().getDeclaringClass(), equalTo(LambdaSignatureTest.class)); assertThat(lambda.getImplMethodKind(), equalTo(MethodHandleInfo.REF_invokeStatic)); assertThat(lambda.getImplMethodSignature(), equalTo("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;")); assertThat(lambda.getImplMethod().getParameterTypes(), arrayContaining(Integer.class, Integer.class)); assertThat(lambda.getInstantiatedMethodType(), equalTo("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;")); }
@SuppressWarnings("unchecked") @Test public void testSerializeStaticCapturing() throws Exception { SerializedLambda serializedLambda = Lambdas.serializeLambda(splusCapturing(42)); assertThat(serializedLambda.getCapturedArgCount(), equalTo(1)); assertThat(serializedLambda.getCapturedArg(0), equalTo(42)); LambdaSignature lambda = new LambdaSignature() .withCapturingClass(serializedLambda.getCapturingClass()) .withInstantiatedMethodType(serializedLambda.getInstantiatedMethodType()) .withFunctionalInterface(serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(serializedLambda.getImplClass(), serializedLambda.getImplMethodKind(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); assertThat(lambda.getCapturingClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getFunctionalInterfaceClass(), equalTo("java/util/function/Function")); assertThat(lambda.getFunctionalInterfaceMethod().getDeclaringClass(), equalTo(Function.class)); assertThat(lambda.getFunctionalInterfaceMethodName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethodSignature(), equalTo("(Ljava/lang/Object;)Ljava/lang/Object;")); assertThat(lambda.getFunctionalInterfaceMethod().getName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethod().getParameterTypes(), arrayContaining(Object.class)); assertThat(lambda.getImplClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getImplMethodKind(), equalTo(MethodHandleInfo.REF_invokeStatic)); assertThat(lambda.getImplMethodSignature(), equalTo("(ILjava/lang/Integer;)Ljava/lang/Integer;")); assertThat(lambda.getImplMethod().getParameterTypes(), arrayContaining(int.class, Integer.class)); assertThat(lambda.getInstantiatedMethodType(), equalTo("(Ljava/lang/Integer;)Ljava/lang/Integer;")); }
@SuppressWarnings("unchecked") @Test public void testSerializeInstanceCapturing() throws Exception { SerializedLambda serializedLambda = Lambdas.serializeLambda(this.splusInstanceCapturing()); assertThat(serializedLambda.getCapturedArgCount(), equalTo(1)); assertThat(serializedLambda.getCapturedArg(0), equalTo(this)); LambdaSignature lambda = new LambdaSignature() .withCapturingClass(serializedLambda.getCapturingClass()) .withInstantiatedMethodType(serializedLambda.getInstantiatedMethodType()) .withFunctionalInterface(serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(serializedLambda.getImplClass(), serializedLambda.getImplMethodKind(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); assertThat(lambda.getCapturingClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getFunctionalInterfaceClass(), equalTo("java/util/function/Function")); assertThat(lambda.getFunctionalInterfaceMethod().getDeclaringClass(), equalTo(Function.class)); assertThat(lambda.getFunctionalInterfaceMethodName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethodSignature(), equalTo("(Ljava/lang/Object;)Ljava/lang/Object;")); assertThat(lambda.getFunctionalInterfaceMethod().getName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethod().getParameterTypes(), arrayContaining(Object.class)); assertThat(lambda.getImplClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getImplMethodKind(), equalTo(MethodHandleInfo.REF_invokeSpecial)); assertThat(lambda.getImplMethodSignature(), equalTo("(Ljava/lang/Integer;)Ljava/lang/Integer;")); assertThat(lambda.getImplMethod().getParameterTypes(), arrayContaining(Integer.class)); assertThat(lambda.getInstantiatedMethodType(), equalTo("(Ljava/lang/Integer;)Ljava/lang/Integer;")); }
default SerializedLambda asSerializedLambda() { try { Method replaceMethod = getClass().getDeclaredMethod("writeReplace"); replaceMethod.setAccessible(true); return (SerializedLambda) replaceMethod.invoke(this); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { throw new RuntimeException(e.getClass().getSimpleName() + ": '" + e.getMessage() + "'", e); } }
default String getResultDescription() { SerializedLambda lambda = asSerializedLambda(); if (! lambda.getImplMethodName().startsWith("lambda$")) { return lambda.getImplMethodName(); } return "boolean"; }
default String getResultDescription() { SerializedLambda lambda = asSerializedLambda(); MethodType lambdaMethodType = MethodType.fromMethodDescriptorString(lambda.getImplMethodSignature(), getClass().getClassLoader()); String resultType = lambdaMethodType.returnType().getSimpleName(); if (! lambda.getImplMethodName().startsWith("lambda$")) { return lambda.getImplMethodName() + " (" + withPrefixedArticle(resultType) + ")"; } return resultType; }
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(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(SerializedLambda.class); assertBothWaysNormalized(keeper, expected); // ... deserialization fails if code was compiled with compiler of different vendor // Object resultRoot = xstream.fromXML(expected); // assertNotNull(resultRoot); }
default Method method() { SerializedLambda lambda = serialized(); Class<?> containingClass = getContainingClass(); return asList(containingClass.getDeclaredMethods()) .stream() .filter(method -> Objects.equals(method.getName(), lambda.getImplMethodName())) .findFirst() .orElseThrow(UnableToGuessMethodException::new); }
/** * Returns the list of {@link CapturedArgument} for the {@link SerializedLambda}. * * @param serializedLambda the {@link SerializedLambda} to analyze. * @return the list of {@link CapturedArgument} */ public static List<CapturedArgument> getCapturedArguments( final SerializedLambda serializedLambda) { final List<CapturedArgument> capturedArguments = new ArrayList<>(); for (int i = 0; i < serializedLambda.getCapturedArgCount(); i++) { capturedArguments.add(new CapturedArgument(serializedLambda.getCapturedArg(i))); } return capturedArguments; }
/** * Returns the {@link SerializedLambdaInfo} for the given {@code expression} * * @param expression the expression to analyze. * @return the corresponding {@link SerializedLambda} * @throws AnalyzeException if something wrong happened (a {@link NoSuchMethodException}, * {@link IllegalArgumentException} or {@link InvocationTargetException} exception * occurred). * * @see http ://docs.oracle.com/javase/8/docs/api/java/lang/invoke/SerializedLambda.html * @see http ://stackoverflow.com/questions/21860875/printing-debug-info-on-errors * -with-java-8-lambda-expressions/21879031 #21879031 */ private static SerializedLambdaInfo getSerializedLambdaInfo(final Object expression) { final Class<?> cl = expression.getClass(); try { final Method m = cl.getDeclaredMethod("writeReplace"); m.setAccessible(true); final Object result = m.invoke(expression); if (result instanceof SerializedLambda) { final SerializedLambda serializedLambda = (SerializedLambda) result; LOGGER.debug(" Lambda FunctionalInterface: {}.{} ({})", serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()); LOGGER.debug(" Lambda Implementation: {}.{} ({})", serializedLambda.getImplClass(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); IntStream .range(0, serializedLambda.getCapturedArgCount()) .forEach( i -> LOGGER .debug( " with Captured Arg(" + i + "): '" + serializedLambda.getCapturedArg(i) + ((serializedLambda.getCapturedArg(i) != null) ? "' (" + serializedLambda.getCapturedArg(i).getClass().getName() + ")" : ""))); return new SerializedLambdaInfo(serializedLambda); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { throw new AnalyzeException( "Failed to find the Serialized form for the given Lambda Expression", e); } return null; }