@@ -286,6 +286,145 @@ public J visitForEachControl(J.ForEachLoop.Control control, RpcReceiveQueue q) {
286286 .getPadding ().withIterable (JRightPadded .build (iterable ));
287287 }
288288
289+ /**
290+ * Sets a final field to a value whose type doesn't match the declared field type.
291+ * Go's AST uses nodes (J.Unary for pointer types, J.MethodDeclaration for func
292+ * literals) in positions where Java's model requires TypeTree or Expression.
293+ */
294+ private static void setFinalField (Object target , String fieldName , Object value ) {
295+ try {
296+ java .lang .reflect .Field f = target .getClass ().getDeclaredField (fieldName );
297+ f .setAccessible (true );
298+ f .set (target , value );
299+ } catch (Exception ignored ) {
300+ }
301+ }
302+
303+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
304+ private J receiveAsJ (@ Nullable Object before , RpcReceiveQueue q ) {
305+ return (J ) ((RpcReceiveQueue ) q ).receive (
306+ before ,
307+ (java .util .function .UnaryOperator ) t -> visitNonNull ((J ) t , q ));
308+ }
309+
310+ @ Override
311+ public J visitArrayType (J .ArrayType arrayType , RpcReceiveQueue q ) {
312+ // Go slice types like []*T have pointer element types (J.Unary) that
313+ // don't implement TypeTree.
314+ J elementType = receiveAsJ (arrayType .getElementType (), q );
315+ if (elementType instanceof TypeTree ) {
316+ arrayType = arrayType .withElementType ((TypeTree ) elementType );
317+ } else if (elementType != null ) {
318+ setFinalField (arrayType , "elementType" , elementType );
319+ }
320+ return arrayType
321+ .withAnnotations (q .receiveList (arrayType .getAnnotations (), a -> (J .Annotation ) visitNonNull (a , q )))
322+ .withDimension (q .receive (arrayType .getDimension (), d -> visitLeftPadded (d , q )))
323+ .withType (q .receive (arrayType .getType (), t -> visitType (t , q )));
324+ }
325+
326+ @ Override
327+ public J visitLiteral (J .Literal literal , RpcReceiveQueue q ) {
328+ literal = literal
329+ .withValue (q .receive (literal .getValue ()))
330+ .withValueSource (q .receive (literal .getValueSource ()))
331+ .withUnicodeEscapes (q .receiveList (literal .getUnicodeEscapes (), s -> {
332+ int valueSourceIndex = q .receive (s != null ? s .getValueSourceIndex () : 0 );
333+ String codePoint = q .receive (s != null ? s .getCodePoint () : null );
334+ return new J .Literal .UnicodeEscape (valueSourceIndex , codePoint );
335+ }));
336+ // Go may send JavaType.Class for int/string literals where Java expects JavaType.Primitive
337+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
338+ JavaType type = (JavaType ) ((RpcReceiveQueue ) q ).receive (
339+ (Object ) literal .getType (),
340+ (java .util .function .UnaryOperator ) t -> visitType ((JavaType ) t , q ));
341+ if (type instanceof JavaType .Primitive ) {
342+ literal = literal .withType ((JavaType .Primitive ) type );
343+ } else if (type != null ) {
344+ setFinalField (literal , "type" , type );
345+ }
346+ return literal ;
347+ }
348+
349+ @ Override
350+ public J visitMethodDeclaration (J .MethodDeclaration method , RpcReceiveQueue q ) {
351+ if (method .getAnnotations ().getName () == null ) {
352+ method = method .getAnnotations ().withName (
353+ new J .MethodDeclaration .IdentifierWithAnnotations (null , null ));
354+ }
355+ method = method
356+ .withLeadingAnnotations (q .receiveList (method .getLeadingAnnotations (),
357+ a -> (J .Annotation ) visitNonNull (a , q )))
358+ .withModifiers (q .receiveList (method .getModifiers (),
359+ m -> (J .Modifier ) visitNonNull (m , q )))
360+ .getPadding ().withTypeParameters (q .receive (
361+ method .getPadding ().getTypeParameters (),
362+ tp -> (J .TypeParameters ) visitNonNull (tp , q )));
363+
364+ // Go return types can be pointer types (*T → J.Unary), slice types,
365+ // or Go-specific nodes that don't implement TypeTree.
366+ J returnType = receiveAsJ (method .getReturnTypeExpression (), q );
367+ if (returnType instanceof TypeTree ) {
368+ method = method .withReturnTypeExpression ((TypeTree ) returnType );
369+ } else if (returnType != null ) {
370+ setFinalField (method , "returnTypeExpression" , returnType );
371+ }
372+
373+ return method
374+ .getAnnotations ().withName (method .getAnnotations ().getName ()
375+ .withAnnotations (q .receiveList (
376+ method .getAnnotations ().getName ().getAnnotations (),
377+ a -> (J .Annotation ) visitNonNull (a , q ))))
378+ .withName (q .receive (method .getName (),
379+ n -> (J .Identifier ) visitNonNull (n , q )))
380+ .getPadding ().withParameters (q .receive (
381+ method .getPadding ().getParameters (), p -> visitContainer (p , q )))
382+ .getPadding ().withThrows (q .receive (
383+ method .getPadding ().getThrows (), t -> visitContainer (t , q )))
384+ .withBody (q .receive (method .getBody (),
385+ b -> (J .Block ) visitNonNull (b , q )))
386+ .getPadding ().withDefaultValue (q .receive (
387+ method .getPadding ().getDefaultValue (),
388+ d -> visitLeftPadded (d , q )))
389+ .withMethodType (q .receive (method .getMethodType (),
390+ t -> (JavaType .Method ) visitType (t , q )));
391+ }
392+
393+ @ Override
394+ public J visitReturn (J .Return retrn , RpcReceiveQueue q ) {
395+ // Go function literals in return position are J.MethodDeclaration, not Expression
396+ J expr = receiveAsJ (retrn .getExpression (), q );
397+ if (expr instanceof Expression ) {
398+ return retrn .withExpression ((Expression ) expr );
399+ } else if (expr != null ) {
400+ setFinalField (retrn , "expression" , expr );
401+ }
402+ return retrn ;
403+ }
404+
405+ @ Override
406+ public J visitVariableDeclarations (J .VariableDeclarations variableDecls , RpcReceiveQueue q ) {
407+ variableDecls = variableDecls
408+ .withLeadingAnnotations (q .receiveList (variableDecls .getLeadingAnnotations (),
409+ a -> (J .Annotation ) visitNonNull (a , q )))
410+ .withModifiers (q .receiveList (variableDecls .getModifiers (),
411+ m -> (J .Modifier ) visitNonNull (m , q )));
412+
413+ // Go pointer/slice/map types don't always implement TypeTree
414+ J typeExpr = receiveAsJ (variableDecls .getTypeExpression (), q );
415+ if (typeExpr instanceof TypeTree ) {
416+ variableDecls = variableDecls .withTypeExpression ((TypeTree ) typeExpr );
417+ } else if (typeExpr != null ) {
418+ setFinalField (variableDecls , "typeExpression" , typeExpr );
419+ }
420+
421+ variableDecls = variableDecls .withVarargs (
422+ q .receive (variableDecls .getVarargs (), v -> visitSpace (v , q )));
423+ return variableDecls .getPadding ().withVariables (
424+ q .receiveList (variableDecls .getPadding ().getVariables (),
425+ v -> visitRightPadded (v , q )));
426+ }
427+
289428 @ Override
290429 public J visitImport (J .Import importStmt , RpcReceiveQueue q ) {
291430 importStmt = importStmt .getPadding ().withStatic (
0 commit comments