microsoft / microsoft/durabletask-java
Customizable Serialization for Activity Return Values in Durable Functions
オープン
まだ誰も着手していません。
P2
- 主要言語
- Java
- スター
- 29
- フォーク
- 18
- 平均マージ
- 1日 10時間
- マージ済み PR(30日)
- 2
説明
What’s the problem?
Hey👋,
I'm working with Durable Functions in Java, and I’ve encountered an issue with how activity return values are serialized. Specifically:
- Activity functions return POJOs annotated with Jackson and Gson and having subTypes, which is deserialized using Gson when entering the activity but none is used for serializing return value.
- This creates inconsistencies.
- There's no way to customize the serialization mechanism for Durable Functions activities.
- Raises an Exception of InvalidTypeIdException because the type is missing at com.microsoft.durabletask.JacksonDataConverter#deserialize.
How to reproduce it?
Here’s a minimal Durable Function example where an Activity returns a POJO, but the Azure Functions Java Worker does not deserialize it properly:
1️⃣ POJO with Jackson & Gson annotations and Subtypes
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.*;
import java.io.IOException;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = AdminUser.class, name = "admin"),
@JsonSubTypes.Type(value = RegularUser.class, name = "regular")
})
@JsonAdapter(UserTypeAdapter.class)
public abstract class User {
private String id;
private String name;
public User() {}
public User(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() { return id; }
public String getName() { return name; }
}
public class AdminUser extends User {
private int adminLevel;
public AdminUser() {}
public AdminUser(String id, String name, int adminLevel) {
super(id, name);
this.adminLevel = adminLevel;
}
}
public class RegularUser extends User {
private String membershipStatus;
public RegularUser() {}
public RegularUser(String id, String name, String membershipStatus) {
super(id, name);
this.membershipStatus = membershipStatus;
}
}
public class UserTypeAdapter extends TypeAdapter<User> {
@Override
public void write(JsonWriter out, User user) throws IOException {
out.beginObject();
out.name("type").value(user instanceof AdminUser ? "admin" : "regular");
out.name("id").value(user.getId());
out.name("name").value(user.getName());
if (user instanceof AdminUser) {
out.name("adminLevel").value(((AdminUser) user).adminLevel);
} else if (user instanceof RegularUser) {
out.name("membershipStatus").value(((RegularUser) user).membershipStatus);
}
out.endObject();
}
@Override
public User read(JsonReader in) throws IOException {
in.beginObject();
String type = "";
String id = "";
String name = "";
int adminLevel = 0;
String membershipStatus = "";
while (in.hasNext()) {
String fieldName = in.nextName();
switch (fieldName) {
case "type":
type = in.nextString();
break;
case "id":
id = in.nextString();
break;
case "name":
name = in.nextString();
break;
case "adminLevel":
adminLevel = in.nextInt();
break;
case "membershipStatus":
membershipStatus = in.nextString();
break;
default:
in.skipValue();
break;
}
}
in.endObject();
return "admin".equals(type) ? new AdminUser(id, name, adminLevel) : new RegularUser(id, name, membershipStatus);
}
}
What do you want to happen?
✅ Supporting GSON for serialization.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
com.microsoft.durabletask.JacksonDataConverter から始め、activity の戻り値がどのようにシリアライズされ、その後デシリアライズされるかを追跡します。提供されている polymorphic な User の例を使って失敗の原因を理解し、次に設定可能な Gson serializer をどのように組み込めるかを判断します。Gson アノテーションを使用する activity POJO が、型の欠落による InvalidTypeIdException なしにラウンドトリップできれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- java
- 領域
- backend
- issue の種類
- 機能追加
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 35/100