-
Notifications
You must be signed in to change notification settings - Fork 947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Auto generate unknown fallback #1561
Conversation
bed706e
to
05c8564
Compare
Feat: Auto generate unknown fallback class for interface classes Feat: Auto generate unknown fallback class for interface classes
05c8564
to
5d53f18
Compare
generate-code.py
Outdated
|
||
CLASS_TEMPLATE = """package {package}; | ||
|
||
public record {unknown_class_name}() implements {interface_name} {{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if an interface requires implementation class has to have some fields like MessageContent
and UnknownMessageContent
?
Lines 19 to 20 in f79e256
public record UnknownMessageContent(String id) implements MessageContent { | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't compile. though the current patch seems working as of now, but given cases like this, modifying the generator's code might be a better choice.
In the generator's #postProcessModels
, it can handle all models, so wouldn't it be better to create an unknown* class (like UnknownMessageContent
) that implements the interface here?
line-bot-sdk-java/generator/src/main/java/com/linecorp/bot/codegen/LineJavaCodegenGenerator.java
Lines 111 to 138 in f79e256
public ModelsMap postProcessModels(ModelsMap objs) { | |
ModelsMap modelsMap = super.postProcessModels(objs); | |
for (ModelMap model : modelsMap.getModels()) { | |
CodegenModel codegenModel = model.getModel(); | |
// remove the `type` field from child classes due to remove duplicated type field with `@JsonTypeName`. | |
if (codegenModel.parent != null) { | |
codegenModel.setAllVars(codegenModel.getAllVars().stream() | |
.filter(codegenProperty -> !codegenProperty.name.equals("type")) | |
.collect(Collectors.toList())); | |
} | |
// if the class have a parent, set ` implements ${parent}`. | |
// and put @JsonTypeName annotation. | |
if (codegenModel.parent != null) { | |
addImplements(codegenModel, codegenModel.parent); | |
} | |
// Implements ReplyEvent if the class has "replyToken" field. | |
if (codegenModel.parent != null && codegenModel.parent.equals("Event")) { | |
if (codegenModel.vars.stream().anyMatch(codegenProperty -> codegenProperty.name.equals("replyToken"))) { | |
addImplements(codegenModel, "ReplyEvent"); | |
} | |
} | |
} | |
return modelsMap; | |
} |
(just an idea, probably this doesn't work without modification)
@Override
public ModelsMap postProcessModels(ModelsMap objs) {
ModelsMap modelsMap = super.postProcessModels(objs);
+ List<ModelMap> additionalModels = new ArrayList<>();
for (ModelMap model : modelsMap.getModels()) {
CodegenModel codegenModel = model.getModel();
// remove the `type` field from child classes due to remove duplicated type field with `@JsonTypeName`.
if (codegenModel.parent != null) {
codegenModel.setAllVars(codegenModel.getAllVars().stream()
.filter(codegenProperty -> !codegenProperty.name.equals("type"))
.collect(Collectors.toList()));
}
// if the class have a parent, set ` implements ${parent}`.
// and put @JsonTypeName annotation.
if (codegenModel.parent != null) {
addImplements(codegenModel, codegenModel.parent);
}
// Implements ReplyEvent if the class has "replyToken" field.
if (codegenModel.parent != null && codegenModel.parent.equals("Event")) {
if (codegenModel.vars.stream().anyMatch(codegenProperty -> codegenProperty.name.equals("replyToken"))) {
addImplements(codegenModel, "ReplyEvent");
}
}
+ // Set additional unknown* class for jackson's defaultImpl to have unknwon* class as fallback
+ if (codegenModel.discriminator != null) {
+ String fallbackModelName = "Unknown" + codegenModel.classname;
+ CodegenModel fallbackModel = new CodegenModel();
+ fallbackModel.name = fallbackModelName;
+ // set some fields
+ // ...
+ addImplements(fallbackModel, codegenModel.classname);
+ ModelMap fallbackModelMap = new ModelMap();
+ fallbackModelMap.put("model", fallbackModel);
+ additionalModels.add(fallbackModelMap);
}
}
+ modelsMap.getModels().addAll(additionalModels);
return modelsMap;
}
bed9b99
to
1fc45d9
Compare
1fc45d9
to
461ca1c
Compare
@Yang-33 |
generator/src/main/java/com/linecorp/bot/codegen/LineJavaCodegenGenerator.java
Outdated
Show resolved
Hide resolved
e395b61
to
1850e1b
Compare
1850e1b
to
40c842c
Compare
Resolve #1537.
#1462
Summary
Previously, in the line-bot-sdk-java, the
Unknown
class was manually implemented and used as thedefaultImpl
(fallback) in@JsonTypeInfo
. However, with the transition to generating code from OpenAPI definitions, generating theUnknown
class directly from the OpenAPI spec became challenging. Consequently, the fallback option was disabled.This change created an issue when decoding webhooks. The type field in webhooks may receive new values as future features are developed. If an older SDK version encounters these new values, it could crash while parsing the webhook.
This PR aims to re-enable the fallback option by adding code that automatically generates the
Unknown
class from the Java code produced by OpenAPI,even if the method is a bit rough or not entirely elegant. This ensures that we can maintain the fallback mechanism under OpenAPI management.