public void testWriteAnonymousClass() { // final List<String> baz = Arrays.asList("foo", "bar"); // new AbstractList<String>() { // public int size() { // return baz.size(); // } // public String get(int index) { // return ((String) baz.get(index)).toUpperCase(); // } // } final ParameterExpression bazParameter = Expressions.parameter(Types.of(List.class, String.class), "baz"); final ParameterExpression indexParameter = Expressions.parameter(Integer.TYPE, "index"); BlockExpression e = Expressions.block( Expressions.declare( Modifier.FINAL, bazParameter, Expressions.call( Arrays.class, "asList", Arrays.<Expression>asList( Expressions.constant("foo"), Expressions.constant("bar")))), Expressions.statement( Expressions.new_( Types.of(AbstractList.class, String.class), Collections.<Expression>emptyList(), Arrays.<MemberDeclaration>asList( Expressions.fieldDecl( Modifier.PUBLIC | Modifier.FINAL, Expressions.parameter(String.class, "qux"), Expressions.constant("xyzzy")), Expressions.methodDecl( Modifier.PUBLIC, Integer.TYPE, "size", Collections.<ParameterExpression>emptyList(), Blocks.toFunctionBlock( Expressions.call( bazParameter, "size", Collections.<Expression>emptyList()))), Expressions.methodDecl( Modifier.PUBLIC, String.class, "get", Arrays.asList(indexParameter), Blocks.toFunctionBlock( Expressions.call( Expressions.convert_( Expressions.call( bazParameter, "get", Arrays.<Expression>asList(indexParameter)), String.class), "toUpperCase", Collections.<Expression>emptyList()))))))); assertEquals( "{\n" + " final java.util.List<String> baz = java.util.Arrays.asList(\"foo\", \"bar\");\n" + " new java.util.AbstractList<String>(){\n" + " public final String qux = \"xyzzy\";\n" + " public int size() {\n" + " return baz.size();\n" + " }\n" + "\n" + " public String get(int index) {\n" + " return ((String) baz.get(index)).toUpperCase();\n" + " }\n" + "\n" + " };\n" + "}\n", Expressions.toString(e)); }
@Override void accept(ExpressionWriter writer, int lprec, int rprec) { // "new Function1() { // public Result apply(T1 p1, ...) { // <body> // } // // bridge method // public Object apply(Object p1, ...) { // return apply((T1) p1, ...); // } // } // // if any arguments are primitive there is an extra bridge method: // // new Function1() { // public double apply(double p1, int p2) { // <body> // } // // box bridge method // public Double apply(Double p1, Integer p2) { // return apply(p1.doubleValue(), p2.intValue()); // } // // bridge method // public Object apply(Object p1, Object p2) { // return apply((Double) p1, (Integer) p2); // } List<String> params = new ArrayList<String>(); List<String> bridgeParams = new ArrayList<String>(); List<String> bridgeArgs = new ArrayList<String>(); List<String> boxBridgeParams = new ArrayList<String>(); List<String> boxBridgeArgs = new ArrayList<String>(); for (ParameterExpression parameterExpression : parameterList) { final Type parameterType = parameterExpression.getType(); final Type parameterBoxType = Types.box(parameterType); final String parameterBoxTypeName = Types.className(parameterBoxType); params.add(parameterExpression.declString()); bridgeParams.add(parameterExpression.declString(Object.class)); bridgeArgs.add("(" + parameterBoxTypeName + ") " + parameterExpression.name); boxBridgeParams.add(parameterExpression.declString(parameterBoxType)); boxBridgeArgs.add( parameterExpression.name + (Primitive.is(parameterType) ? "." + Primitive.of(parameterType).primitiveName + "Value()" : "")); } Type bridgeResultType = Functions.FUNCTION_RESULT_TYPES.get(this.type); if (bridgeResultType == null) { bridgeResultType = body.getType(); } Type resultType2 = bridgeResultType; if (bridgeResultType == Object.class && !params.equals(bridgeParams) && !(body.getType() instanceof TypeVariable)) { resultType2 = body.getType(); } String methodName = getAbstractMethodName(); writer .append("new ") .append(type) .append("()") .begin(" {\n") .append("public ") .append(Types.className(resultType2)) .list(" " + methodName + "(", ", ", ") ", params) .append(Blocks.toFunctionBlock(body)); // Generate an intermediate bridge method if at least one parameter is // primitive. if (!boxBridgeParams.equals(params)) { writer .append("public ") .append(Types.boxClassName(bridgeResultType)) .list(" " + methodName + "(", ", ", ") ", boxBridgeParams) .begin("{\n") .list("return " + methodName + "(\n", ",\n", ");\n", boxBridgeArgs) .end("}\n"); } // Generate a bridge method. Argument types are looser (as if every // type parameter is set to 'Object'). // // Skip the bridge method if there are no arguments. It would have the // same overload as the regular method. if (!bridgeParams.equals(params)) { writer .append("public ") .append(Types.boxClassName(bridgeResultType)) .list(" " + methodName + "(", ", ", ") ", bridgeParams) .begin("{\n") .list("return " + methodName + "(\n", ",\n", ");\n", bridgeArgs) .end("}\n"); } writer.end("}\n"); }