Skip to content

Register JavaType.ShallowClass codec on the Python RPC side#7441

Merged
knutwannheden merged 1 commit intomainfrom
register-shallowclass-codec-in-py/cs/go-receivers
Apr 21, 2026
Merged

Register JavaType.ShallowClass codec on the Python RPC side#7441
knutwannheden merged 1 commit intomainfrom
register-shallowclass-codec-in-py/cs/go-receivers

Conversation

@knutwannheden
Copy link
Copy Markdown
Contributor

Motivation

Production SB4 runs in rewrite-pip (the Python-side RPC runtime) were failing with:

io.moderne.jsonrpc.JsonRpcException: {code=-32603, message='No RPC codec registered on
the Python side for 'org.openrewrite.java.tree.JavaType$ShallowClass'. The remote side
has a codec and sent property messages that will not be consumed, causing RPC queue
desynchronization.'}

JavaType.ShallowClass is the placeholder used when full JVM type resolution isn't
available. It's a subclass of JavaType.Class with the same wire shape but a distinct
type name — and the Python RPC side wasn't registering a codec for it, so any Java
recipe that sent a ShallowClass to the Python process deadlocked the queue.

I audited the three non-Java RPC implementations:

  • Python (rewrite-python) — no codec registered for JavaType$ShallowClass.
    Fixed here.
  • C# (rewrite-csharp) — already works. FromJavaTypeNameByConvention resolves
    org.openrewrite.java.tree.JavaType$ShallowClass to the existing nested
    OpenRewrite.Java.JavaType+ShallowClass class via reflection, and
    JavaReceiver.VisitType's case JavaType.Class cls: matches ShallowClass through
    inheritance. On the send side, ToJavaTypeName handles nested types recursively and
    produces the correct Java FQN.
  • Go (rewrite-go) — already works for the receive path. The factory for
    JavaTypeShallowClassKind is registered in rewrite-go/pkg/rpc/registry.go,
    producing a *JavaTypeClass instance that the visitor dispatches to VisitClass.
    Go has no separate JavaTypeShallowClass struct by design — all class-like types
    collapse to *JavaTypeClass, so the Go process never constructs a ShallowClass
    to send.

Summary

  • Factored out _receive_java_type_class_fields in python_receiver.py so the same
    field-consumption logic can populate either a JT.Class or a JT.ShallowClass.
  • Registered a codec + factory for org.openrewrite.java.tree.JavaType$ShallowClass
    on the Python side.
  • On the sender side, added an isinstance(obj, JavaType.ShallowClass) check before
    the JavaType.Class check in send_queue.py so ShallowClass instances round-trip
    with the correct Java type name (the existing check would have collapsed them into
    JavaType$Class because ShallowClass inherits from Class).

Test plan

  • Verified the codec and factory are registered under the expected Java type
    name, and that RpcSendQueue._get_value_type() returns
    JavaType$ShallowClass for a JT.ShallowClass() and JavaType$Class for a
    JT.Class().

This PR does not by itself fix the production failure — the fix lands on the
Python-side runtime and needs a rewrite-pip release before the next SB4 flagship
run will pick it up.

When Java sends a `JavaType$ShallowClass` over RPC, the Python side had
no codec registered and threw:

    No RPC codec registered on the Python side for
    'org.openrewrite.java.tree.JavaType$ShallowClass'

`ShallowClass` extends `Class` in Java (and in Python's `support_types`),
so its wire format is identical — only the Java class name differs.

- `python_receiver.py`: factor out `_receive_java_type_class_fields` and
  register a `JavaType$ShallowClass` codec that constructs
  `JT.ShallowClass()` while consuming the same field sequence as `Class`.
- `send_queue.py`: check `isinstance(obj, JavaType.ShallowClass)` before
  the `JavaType.Class` check so Python-created `ShallowClass` instances
  round-trip with the correct type name.

C# already handles `JavaType$ShallowClass` — reflection-based type
resolution resolves `JavaType+ShallowClass` and `VisitType`'s
`case JavaType.Class cls:` matches via inheritance. Go collapses
`ShallowClass` into `*JavaTypeClass` by design (no separate struct);
the receive-side factory for `JavaTypeShallowClassKind` is already
registered.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Apr 21, 2026
@knutwannheden knutwannheden merged commit 2932305 into main Apr 21, 2026
1 check passed
@knutwannheden knutwannheden deleted the register-shallowclass-codec-in-py/cs/go-receivers branch April 21, 2026 08:28
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant