Proposal for new project based on Jackson Mixins

136 views
Skip to first unread message

Andy McCright

unread,
Jun 1, 2020, 1:42:52 PM6/1/20
to Eclipse MicroProfile
Hi All,

In GraphQL we were looking at solving a problem that may be common across multiple MP (and Jakarta, etc.) projects: the ability to "annotate" a type or method when we don't have access to the source code.  This is discussed in detail in issue 111.

In my experience, I've seen several shops where they use a third-party library and want to enhance it.  As a concrete example, a user might take an entity class that represents weather patterns from NOAA or weather.com, etc. Then they want to change a few things when writing it to JSON or the GraphQL schema, etc.  The easiest thing to do would be to add a `@JsonbProperty("newName")` to the field, but if they don't control the source code for that entity class, then what?  There are some things they could do like inheriting from the base class and then using their own custom sub-class (assuming the base-class wasn't final).  That might work in some cases...

Jackson Mixins seems like a very clever approach to solving this problem.  Basically you annotate a new abstract class or interface that represents the real class you wish you could annotate. Then in your abstract class or interface, you specify the target class, and now Jackson will treat that target class and it's methods as if it were annotated with the same annotations as on the new abstract class/interface.  

In MP, I can see applications of this for things like MP GraphQL, Rest Client (imagine cases where the client interface or some provider is in a third-party jar), Fault Tolerance (i.e. adding some robustness to third-party libraries), Metrics (tracking stats for classes/methods in third-party libraries), and several Jakarta projects like JSON-B, Bean Validation, JPA, etc.

Any thoughts on something like this?  We could add it directly into MP GraphQL, but it seems like something that would be more useful if we applied it more broadly.

Thanks,

Andy

Ivar Grimstad

unread,
Jun 2, 2020, 2:18:57 AM6/2/20
to Eclipse MicroProfile

I like the idea! 
Just a thought, isn't this something that would fit within the scope of Jakarta JSON Binding (https://jakarta.ee/specifications/jsonb/). It feels like a bit of overhead to establish an entire project for this feature?

Ivar

Rüdiger zu Dohna

unread,
Jun 2, 2020, 2:34:25 AM6/2/20
to Eclipse MicroProfile
Hi,

I'd like to add other cases where the lack of a standard annotation resolution mechanism hurts:
  • @Stereotype annotations are only respected inside CDI. E.g. EJB annotations like @Stateless can't be moved out into a stereotype like @Boundary.
  • It's very common that if a method or field can be annotated, but is not, the same annotation on the class can serve as a fallback.
  • Sometimes it may be useful to have annotations on the package as a fallback for the class (or method/field) level annotations.
  • E.g. annotating a POJO property with GraphQL @Name is basically another way of annotating it as a @JsonbProperty name; it's a kind of aliasing.
Instead of re-implementing these mechanisms again and again and living with inconsistent behavior because some features are supported for some annotations but not for others, we may define a meta-standard for annotation resolution.

Just my 2¢
Rüdiger

Emily Jiang

unread,
Jun 2, 2020, 10:20:52 AM6/2/20
to Eclipse MicroProfile
If this annotation is to be added to Jakarta EE, I think it fits in better with Jakarta Common annotations https://github.com/eclipse-ee4j/common-annotations-api/tree/master/api/src/main/java/jakarta/annotation.

Emily

Emily Jiang

unread,
Jun 2, 2020, 10:34:21 AM6/2/20
to Eclipse MicroProfile
My comments are inline.


On Tuesday, June 2, 2020 at 7:34:25 AM UTC+1, Rüdiger zu Dohna wrote:
Hi,

I'd like to add other cases where the lack of a standard annotation resolution mechanism hurts:
  • @Stereotype annotations are only respected inside CDI. E.g. EJB annotations like @Stateless can't be moved out into a stereotype like @Boundary.
@Stateless  can be replaced by @Depended. I am not sure why you need a stereotype. By the way, @Stereotype is a CDI annotation and it only works with CDI. I don't think it can be lifted out without the mention of CDI.

  • It's very common that if a method or field can be annotated, but is not, the same annotation on the class can serve as a fallback.
This is defined in the Jakarta Annotation spec.

  • Sometimes it may be useful to have annotations on the package as a fallback for the class (or method/field) level annotations.

  • E.g. annotating a POJO property with GraphQL @Name is basically another way of annotating it as a @JsonbProperty name; it's a kind of aliasing.
As for annotation on the package, where do you put the annoation? In order to support this, we might need to introduce the package-info.java concept. I am not sure how useful for support that as potentially the classes might not want to inherit the annotation. This also could introduce problems when adding more and more classes without noticing the package-level annotation as it is not directly visible.

> Instead of re-implementing these mechanisms again and again and living with inconsistent behavior because some features are supported for some annotations but not for others, we may define a meta-standard for annotation resolution.

I think the commonly shared annotations should be defined in Jakarta Common Annotation as ementioned above.

Thanks
Emily

Just my 2¢
Rüdiger

Rüdiger zu Dohna

unread,
Jun 2, 2020, 12:23:01 PM6/2/20
to Eclipse MicroProfile
comments inline

 
On Tuesday, June 2, 2020 at 7:34:25 AM UTC+1, Rüdiger zu Dohna wrote:
Hi,

I'd like to add other cases where the lack of a standard annotation resolution mechanism hurts:
  • @Stereotype annotations are only respected inside CDI. E.g. EJB annotations like @Stateless can't be moved out into a stereotype like @Boundary.
@Stateless  can be replaced by @Depended. I am not sure why you need a stereotype. By the way, @Stereotype is a CDI annotation and it only works with CDI. I don't think it can be lifted out without the mention of CDI.

@Stateless adds quite some functionality, e.g. pooling, transactions, etc. It currently has to be added directly to the class. The same is true for, e.g., JPA: if I have a POJO that I use as DTO, I'll add JSON-B annotations; and if I want to also store it in a DB, I have to add `@Entity`, etc. It would be nice, if I could annotate such a POJO with a custom stereotype annotation, but JPA, EJB, etc. don't consider those indirect annotations.

I've seen cases where several classes had more than 10 annotations, and most of them where the same. Stereotypes would make the code much more readable, as you specify the role of a class, not the technical bindings it needs for that role.
  • It's very common that if a method or field can be annotated, but is not, the same annotation on the class can serve as a fallback.
This is defined in the Jakarta Annotation spec.

Sure, but the implementation for resolving such an annotation is implemented every time; it's not much by itself, but it sums up.
  • Sometimes it may be useful to have annotations on the package as a fallback for the class (or method/field) level annotations.

  • E.g. annotating a POJO property with GraphQL @Name is basically another way of annotating it as a @JsonbProperty name; it's a kind of aliasing.
As for annotation on the package, where do you put the annoation? In order to support this, we might need to introduce the package-info.java concept. I am not sure how useful for support that as potentially the classes might not want to inherit the annotation. This also could introduce problems when adding more and more classes without noticing the package-level annotation as it is not directly visible.

Yes, this may be a problem. But it's left to the discretion of the application developers, and they may be fine with this.

> Instead of re-implementing these mechanisms again and again and living with inconsistent behavior because some features are supported for some annotations but not for others, we may define a meta-standard for annotation resolution.

I think the commonly shared annotations should be defined in Jakarta Common Annotation as ementioned above.

I think it would be helpful to have a spec for resolving annotations in a standard way. This would include mixins as well as stereotypes and maybe more. If this "meta-spec" was accepted by all other specs (MP-*, EJB, JPA, JSON-B, etc., etc.), we'd have a consistent way to use these on all our annotations.


Rüdiger

Ivar Grimstad

unread,
Jun 2, 2020, 1:37:23 PM6/2/20
to Eclipse MicroProfile
The "MIxin" feature is planned to be added to the next version of JSON-B. The feature is discussed here: https://github.com/eclipse-ee4j/jsonb-api/issues/88 

Ivar

Emily Jiang

unread,
Jun 2, 2020, 1:39:39 PM6/2/20
to Eclipse MicroProfile
@Stateless adds quite some functionality, e.g. pooling, transactions, etc. It currently has to be added directly to the class. The same is true for, e.g., JPA: if I have a POJO that I use as DTO, I'll add JSON-B annotations; and if I want to also store it in a DB, I have to add `@Entity`, etc. It would be nice, if I could annotate such a POJO with a custom stereotype annotation, but JPA, EJB, etc. don't consider those indirect annotations.

I heard @Stateless performance is better than Dependent scoped beans, as the instance you got is potentially reusable, which is managed by the pool. For Transactions, I think it is better to use @Transactional and CDI beans are perfectly fine. The reason I am pushing for CDI is that I think in the long run CDI will supercede EJB. 

I've seen cases where several classes had more than 10 annotations, and most of them where the same. Stereotypes would make the code much more readable, as you specify the role of a class, not the technical bindings it needs for that role.

I think you are asking for annotation aggregator not stereotype. The CDI stereotype has always a scope associated and only can be applied to CDI beans. If no explicit scope is specified, Dependent scope is used.


Thanks
Emily

Rüdiger zu Dohna

unread,
Jun 2, 2020, 11:17:33 PM6/2/20
to Eclipse MicroProfile
On Tuesday, June 2, 2020 at 7:39:39 PM UTC+2, Emily Jiang wrote:
I've seen cases where several classes had more than 10 annotations, and most of them where the same. Stereotypes would make the code much more readable, as you specify the role of a class, not the technical bindings it needs for that role.

I think you are asking for annotation aggregator not stereotype. The CDI stereotype has always a scope associated and only can be applied to CDI beans. If no explicit scope is specified, Dependent scope is used.

Maybe David is more capable of describing the point about stereotypes ;-)  (while using a different name for the same basic idea) http://blog.dblevins.com/2012/11/meta-annotations.html


Rüdiger

Andy Guibert

unread,
Jun 3, 2020, 10:52:51 AM6/3/20
to Eclipse MicroProfile
Hi Andy,

I agree with Ivar -- isn't this something more within the scope of JSON-B? Or is JSON-B not an option because GraphQL uses its own variant of a json-ish looking format?

We've discussed this extensively from a JSON-B perspective and my initial thought was to simply copy Jackson Mixin's too, but after some feedback from Romain I realized that Mixins can end up being very clunky in the real world. There are 2 main issues with Mixins:
1) They are not type-safe. The original class changes then the mixin breaks
2) You have to model the entire class via mixin, even if you only want to override a few elements.

Those two issues combined caused us to look for a different solution. We were able to eliminate issue (2), which also helped to mitigate issue (1). Here is an example of what we have come up with so far:

JsonbConfig config = new JsonbConfig()
    .addClassCustomization(
        ClassCustomization.builder(MyClass.class)
            .property("originalName", "newName")  // like @JsonbProperty
            .transient("propertyName")            // like @JsonbTransient
            .creator(...)                         // custom instantiation 
            .build();
    )

If you have further ideas/comments on this topic here is the JSON-B thread: https://github.com/eclipse-ee4j/jsonb-api/issues/88 

Rüdiger zu Dohna

unread,
Jun 4, 2020, 2:10:21 AM6/4/20
to Eclipse MicroProfile
It is something within the scope of JSON-B. But it's also within the scope of GraphQL, EJB, JPA, ........ Using mixins (and the other goodies) is something that would be useful in all JEE and MP standards.

I understand that the ClassCustomization you just proposed is JSON-B specific. This can be a benefit for the developers. But a general concept (and I think mixins in the style of Jackson are) has it's own advantages. Namely you can apply and even mix annotations from different standards in a consistent style and don't have to learn the details for every standard... especially if it's something that you don't need very often, like mixins.

So why not join forces and create a common mechanism that can be introduced into all other standards one-by-one. And as we don't want to share implementations, we'd build a standard for it, too... sort of a meta-standard that all other standards will eventually comply to for the benefit of a consistent developer experience. We can start maybe with GraphQL and JSON-B and if it works out fine, I'm confident that other standards will be glad to follow.

Does that make sense?


BTW: having a common standard to access all annotations would also allow for implementations to use compile-time annotation scanning, which is a prerequisite for Quarkus and others.

Andy McCright

unread,
Jun 4, 2020, 2:02:15 PM6/4/20
to Eclipse MicroProfile
Rüdiger, those are my thoughts as well.  If we only want to limit the scope of the "mixins" to JSON, then JSON-B is the right place for it.  But my proposal (based on some of our previous conversations) was that this could be more broad in scope.  

It does make things more complicated because we would need to weave annotations across multiple technologies.  I think we might want to limit the mixins to CDI-managed beans (which would include GraphQL endpoints, JAX-RS resources/providers, EJBs, etc. - I'm not sure about JPA...) - or like you suggest, just start with MP GraphQL and JSON-B and gradually expand to other technologies.

Thanks, Andy

Andy Guibert

unread,
Jun 4, 2020, 2:20:16 PM6/4/20
to microp...@googlegroups.com
What scope exactly did you have in mind Andy? Were you thinking in terms of use-case scope (i.e. mixins) or in terms of data format (json, xml, graphql-schema)

I really like that Jackson is a generic databinding library -- it's not just limited to JSON<-->Java, but can do other things like XML/YAML/etc. It would be good to have this in MP also, but that might be a separate topic from what you are suggesting.

As others have pointed out, Jakarta Common Annotations seems like a good place for this feature, and then it can be consumed by other specs. Or, since specs _can_ depend on other specs we could just put this functionality in JSON-B and add a soft/hard dependency from JAXRS-->JSONB.

--
You received this message because you are subscribed to a topic in the Google Groups "Eclipse MicroProfile" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/microprofile/oWlIsvb2NEU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to microprofile...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/microprofile/28e0327b-bafd-4058-84d9-bf26edb5cc1co%40googlegroups.com.

Andy McCright

unread,
Jun 8, 2020, 12:29:05 PM6/8/20
to Eclipse MicroProfile
I was thinking the scope could be anything that CDI manages. That way, users could add fault tolerance annotations (or Metrics or OpenTracing or ...) to third-party beans as an example.  It should be possible to do this with a CDI extension.

CDI-managed beans likely wouldn't cover all the scenarios that we'd want though - particularly entity classes for things like adding JSON-B or (gulp) JAXB annotations. So for things like that, we probably would need some sort of extension in the JSON-B spec.  

If we wanted to go further (and I'm not necessarily suggesting that we do), then we could do something at the class transformer or redefiner level so that we could add annotations to any class at load time.  


On Thursday, June 4, 2020 at 1:20:16 PM UTC-5, Andy Guibert wrote:
What scope exactly did you have in mind Andy? Were you thinking in terms of use-case scope (i.e. mixins) or in terms of data format (json, xml, graphql-schema)

I really like that Jackson is a generic databinding library -- it's not just limited to JSON<-->Java, but can do other things like XML/YAML/etc. It would be good to have this in MP also, but that might be a separate topic from what you are suggesting.

As others have pointed out, Jakarta Common Annotations seems like a good place for this feature, and then it can be consumed by other specs. Or, since specs _can_ depend on other specs we could just put this functionality in JSON-B and add a soft/hard dependency from JAXRS-->JSONB.

To unsubscribe from this group and all its topics, send an email to microp...@googlegroups.com.

Werner Keil

unread,
Jun 8, 2020, 3:16:17 PM6/8/20
to Eclipse MicroProfile
Sounds pretty fuzzy and there are all those other features like Metrics etc. so what would be the value of this vs. helping add mixins to the Jakarta JSON specs instead?

Werner

Emily Jiang

unread,
Jun 8, 2020, 6:45:46 PM6/8/20
to Eclipse MicroProfile
What do you mean that CDI manages? Is it a CDI bean, interceptor or something? I think it is just a normal annotation that allows to manipulate a sealed class, which may not be a bean at all, hence my suggestion is to introduce this in the common annotation spec. I think raising an issue in Jakarta common annotation for a discussion might be good. In the meanwhile, prototyping in graphQL for the very scenario and then contribute to common annotations so that other specs can benefit from it. It could be even adopted by JDK, e.g. @Repeatable` annotation.

Thanks,
Emily
Reply all
Reply to author
Forward
0 new messages