Skip to content

Conversation

@edeandrea
Copy link
Contributor

@edeandrea edeandrea commented Oct 23, 2025

An idea for api design. This still allows using Java records to implement the model objects, but also makes these objects backwards-compatible by introducing interfaces & builders.

NOTE I've only applied the pattern to the DocumentResponse so that we can decide if this is a good approach or not. If so, we can apply this pattern to the others.

FIxes #23

@edeandrea
Copy link
Contributor Author

@ThomasVitale @lordofthejars take a look and let me know what you think of this approach. I didn't get into ServiceLoaders or anything like that. I think that overcomplicates things.

@edeandrea edeandrea force-pushed the api-design branch 3 times, most recently from 145e42f to 14aae2d Compare October 23, 2025 20:08
@edeandrea edeandrea marked this pull request as draft October 23, 2025 20:19
Copy link

@lordofthejars lordofthejars left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow almost everything is done hahaha we are almost ready to go. Looks good to me just one small comment.

@edeandrea
Copy link
Contributor Author

Wow almost everything is done hahaha we are almost ready to go.

Well, not really :) This is just a design idea that I've only implemented for one of the model objects to show the idea/pattern. If we want to adopt this pattern then we need to implement it across the board.

Then we need documentation, release automation, etc :)

@lordofthejars
Copy link

Wow almost everything is done hahaha we are almost ready to go.

Well, not really :) This is just a design idea that I've only implemented for one of the model objects to show the idea/pattern. If we want to adopt this pattern then we need to implement it across the board.

Then we need documentation, release automation, etc :)

Perfect, looks good to me, then we erge this one and we adapt the rest of the model, or we push ito this PR?

@edeandrea
Copy link
Contributor Author

Wow almost everything is done hahaha we are almost ready to go.

Well, not really :) This is just a design idea that I've only implemented for one of the model objects to show the idea/pattern. If we want to adopt this pattern then we need to implement it across the board.
Then we need documentation, release automation, etc :)

Perfect, looks good to me, then we erge this one and we adapt the rest of the model, or we push ito this PR?

If we like this model then I'll fill in this PR with the rest of the API (its currently marked as draft). I'd like Thomas to weigh in first though, since he was the one who built the initial version.

@ThomasVitale
Copy link
Contributor

ThomasVitale commented Oct 26, 2025

Thanks for this PR! In general, I like the approach, but I have two concerns:

  • If we configure serialisers/deserializers in the API, then we are forcing the usage of a certain Jackson version and that might be problematic (I guess that was why Initial architecture & purpose #2 (comment)). If we stick to the annotations from the com.fasterxml.jackson.annotation package, they are the same across Jackson 2 and 3 (it's the only module that was not changed), so libraries will be free to use the API with their favourite version of Jackson (or even with another tool).
  • I understand the idea behind the design based on interfaces and default implementation, but I'm a bit worried about the effort it would take us to maintain it manually. Existing generators like openapi-generator or openapi-processor don't have support for this kind of design (as far as I know), so even if we make the OpenAPI spec from Docling work, we might not be able to switch to the generated model in a straightforward way. I know that one of the reason for this design is to ensure backward compatibility, so I started a list of requirements in API Design #23 (comment) to help us decide on the final design. I have a hard time imagining situations where, as a library author, I would want to implement the interfaces myself for the data models (typically, it's the client interface that I would customise). But if that's a use case we want to support, let's add it to the list of requirements. What do you think? @edeandrea @lordofthejars

@edeandrea
Copy link
Contributor Author

Thanks for this PR! In general, I like the approach, but I have two concerns:

  • If we configure serialisers/deserializers in the API, then we are forcing the usage of a certain Jackson version and that might be problematic (I guess that was why Initial architecture & purpose #2 (comment)). If we stick to the annotations from the com.fasterxml.jackson.annotation package, they are the same across Jackson 2 and 3 (it's the only module that was not changed), so libraries will be free to use the API with their favourite version of Jackson (or even with another tool).

Agreed. And I realized that doing this required "leaking" jackson-databind into the api (@tools.jackson.databind.annotation.JsonDeserialize(builder = DocumentResponse.Builder.class) and @tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")

That being said, could that be an implementation detail? Since they are annotations, could we support both jackson databind 2.x & 3.x? But then that would violate #23 (comment).

We definitely need to support both 2.x & 3.x, AND I think backwards-compatibility & immutability is super important.

  • I understand the idea behind the design based on interfaces and default implementation, but I'm a bit worried about the effort it would take us to maintain it manually. Existing generators like openapi-generator or openapi-processor don't have support for this kind of design (as far as I know), so even if we make the OpenAPI spec from Docling work, we might not be able to switch to the generated model in a straightforward way. I know that one of the reason for this design is to ensure backward compatibility, so I started a list of requirements in API Design #23 (comment) to help us decide on the final design. I have a hard time imagining situations where, as a library author, I would want to implement the interfaces myself for the data models (typically, it's the client interface that I would customise). But if that's a use case we want to support, let's add it to the list of requirements. What do you think? @edeandrea @lordofthejars

I agree with what you've said. In a perfect world I'd like to have everything, so maybe we need to prioritize our list of requirements? We all know that software engineering is mostly about understanding that there isn't a "perfect" solution to anything - its about knowing & evaluating trade-offs. I think we need to prioritize our requirements by importance. I've taken a stab at what I think.

Maybe the best solution here is to go back to simple Java Pojos for the model classes and stop trying to be "cute" about it? The code isn't as clean and it allows for mutability, but it also allows for the most customization/generalization?

@lordofthejars
Copy link

Maybe we can start with POJOs and if we see taht the project got a high level of adoption, that lot of different Java frameworks are adopting and so on, then we can always refactor.

@edeandrea edeandrea force-pushed the api-design branch 2 times, most recently from 24a7767 to 6029285 Compare October 27, 2025 18:56
Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
Support both Jackson 2 & Jackson 3

Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
Support both Jackson 2 & Jackson 3

Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
@edeandrea
Copy link
Contributor Author

edeandrea commented Oct 28, 2025

@ThomasVitale @lordofthejars I've found a way to support both Jackson 2 & 3 in the API & client

Since they are annotations, I can have both Jackson 2 & 3 at the API level. Then at the client level I can support both 2 & 3 through a Factory interface, which can detect which client to give based on whats on the classpath.

Support both Jackson 2 & Jackson 3

Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
Support both Jackson 2 & Jackson 3

Signed-off-by: Eric Deandrea <eric.deandrea@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API Design

3 participants