Expected a template that would generate exactly one statement to replace one statement, but generated 2
Hi,
I'm trying to write some Recipes for an API migration (non public API). I'm using version 7.24.0 The class names between the old and the new APIs stayed the same, but the packages have changed and some of the method return types, too.
Let's say before that change, there was the following class:
package oldPackage.A;
class A
{
double getValue() { .. }
}
and now there is:
package newPackage.A;
class A
{
Double getValue() { .. }
}
So I want to convert calls from a.getValue() to a.getValue().doubleValue()
So my Java vistor looks like that:
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx)
{
J.MethodInvocation methodInvocation = super.visitMethodInvocation(method, ctx);
if (methodInvocation != null)
{
Method methodType = methodInvocation.getMethodType();
if (methodType != null)
{
if (methodType.getDeclaringType().getPackageName().startsWith("oldPackage"))
{
@Nullable
Primitive primitiveReturnType = TypeUtils.asPrimitive(methodType.getReturnType());
if (primitiveReturnType == Double)
{
JavaTemplate.Builder value = JavaTemplate.builder(this::getCursor, "#{any(java.lang.Double)}.doubleValue()");
String declaringType = methodType.getDeclaringType().toString();
String newDeclaringType = oldToNewMap.get(declaringType); // returns: "newPackage.A"
doAfterVisit(new ChangeType(declaringType, newDeclaringType, true));
return methodInvocation.withTemplate(value.build(),
methodInvocation.getCoordinates().replace(),
methodInvocation.withDeclaringType(ShallowClass.build(newDeclaringType))); /* new type is on classpath */
}
}
}
}
return methodInvocation;
}
While this seems to work fine for the Java code, there is one Javadoc in the code which states:
import oldPackage.A;
class MyClass
{
/**
* @return {@link A#getValue()}
*/
public double foo()
{
return a.getValue();
}
}
which results in the following IllegalArgumentException:
Expected a template that would generate exactly one statement to replace one statement, but generated 2. Template: __P__.<java.lang.Double>/*__p0__*/p().doubleValue()
Is there something in addition I have to do for the Javadoc? Or is my general approach wrong how I want to replace the method calls?
Hi @ZzetT, thanks for reporting the issue! After a few tests, I think there is a bug in JavaTemplate in regards to JavaDocs. I suspect the issue is related to slight differences between source code and JavaDocs like special characters (#).
We'll take a look!
Hi @traceyyoshima
I think I found another example where the method invocation replacement fails with exactly the same error message:
import oldPackage.A;
class MyClass
{
public void foo()
{
double value = 0;
if ((value = a.getValue()) != 0) {}
}
}
I debugged it a bit and saw that the resulting stub looks like that:
class __P__ { static native <T> T p(); static native <T> T[] arrp(); static native boolean booleanp(); static native byte bytep(); static native char charp(); static native double doublep(); static native int intp(); static native long longp(); static native short shortp(); static native float floatp();}class __M__ { static native Object any(Object o); static native <T> Object anyT();}class A{
public void foo(){
double value =0;
boolean __b9__ =value =
/*__TEMPLATE__*/__P__.<java.lang.Double>/*__p0__*/p().doubleValue()
;;}}
As you can see, for some reason it thinks that (value = a.getValue()) is a boolean.
I think I found another example where the method invocation replacement fails with exactly the same error message:
@ZzetT Thanks for reporting this issue too! I created a new issue based on what you reported here.
@ZzetT I am closing this one since the related issue https://github.com/openrewrite/rewrite/issues/2090 has been completed. Please re-open if the bug persists.
Hi @pway99 ,
I hope it didn't lead to confusion that I posted two different problems for the same error message:
- The first one was about a problem with the JavaDoc but I don't see a ticket where this was fixed
- The second one was related to an assignment within an if statement which was fixed with #2090
So from my understanding the first one is still a problem right?
@pway99 just making sure you see @ZzetT 's comment - was the JavaDoc issues resolved as well?
Thanks for the clarification, @ZzetT. I'm unaware of a fix for the JavaDoc issue and will re-open this one.
@ZzetT I'm going to edit the issue to clarify this is to track an issue in updating method invocations in JavaDocs.
Note: JavaDocs do not allow chained method invocations. {@link ...} and @see much follow the following syntax: package.class#member. So, in this case, the JavaTemplate cannot make the appropriate update to the MethodInvocation without some type of contextual transformation to a JavaDoc.