-
Notifications
You must be signed in to change notification settings - Fork 12
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
Improve developer experience and documentation of registering custom ProblemPostProcessor
#312
Conversation
ProblemPostProcessor
@chberger please also have a look, for some reason I'm not able to add you as a official 'reviewer' |
Will take a look later this evening on this. |
...ime/src/main/java/com/tietoevry/quarkus/resteasy/problem/postprocessing/ProblemRecorder.java
Show resolved
Hide resolved
Nice and clean 👍🏻 |
@chberger I'm gonna merge this now, but if you have any feedback from a user (developer) point of view feel free. I'm not releasing it to maven central yet, so there'll still be time for enhancements. |
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.
Overall it looks very good! I've dropped just some minor comments.
Example: | ||
```java | ||
@ApplicationScoped | ||
@Startup // makes sure bean is instantiated eagerly on startup |
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.
Why would a user instantiate such a bean eagerly? AFAIK you register the bean(s) via a static main method (STATIC_INIT) anyway. If your intention is to avoid that Quarkus removes the "unused" bean, I would recommend to use @io.quarkus.arc.Unremovable
instead.
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.
Registering CDI beans as postprocessors happens in runtime (RUNTIME_INIT):
CDI.current().select(ProblemPostProcessor.class)
.forEach(ExceptionMapperBase.postProcessorsRegistry::register);
If you reference your postprocessor from other beans then this annotation is not needed (Quarkus will create and register it as bean in CDI on startup), but if it's not (and I believe it to be true in most cases) this bean will never be created.
@Unremovable
- as far as I undestand - does not affect how the bean is instantiated (lazily or eagerly) - from this extension's point of view Quarkus can remove this bean immediately after startup. But the bean needs to be registered in CDI in RUNTIME_INIT phase for this autoregistration to work correctly.
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.
Registering CDI beans as postprocessors happens in runtime (RUNTIME_INIT):
CDI.current().select(ProblemPostProcessor.class) .forEach(ExceptionMapperBase.postProcessorsRegistry::register);
Sure, my fault.
If you reference your postprocessor from other beans then this annotation is not needed (Quarkus will create and register it as bean in CDI on startup), but if it's not (and I believe it to be true in most cases) this bean will never be created.
@Unremovable
- as far as I undestand - does not affect how the bean is instantiated (lazily or eagerly) - from this extension's point of view Quarkus can remove this bean immediately after startup. But the bean needs to be registered in CDI in RUNTIME_INIT phase for this autoregistration to work correctly.
Marking a bean @Unremovable
is mentioned in the offical guide especially for that case u have implemented:
Please refer to Remove unused beans.
From my understanding, although the bean looks "unused", it won't get removed. Exactly what we want. Thus a proxy gets instantiated (since it is @ApplicationScoped see nonstandard features) and lazily created when registered at RUNTIME_INIT
. Otherwise I cannot explain why this code works ..
@ApplicationScoped
@Unremovable
public class TestProcessor implements ProblemPostProcessor {
@Override
public HttpProblem apply(HttpProblem problem, ProblemContext context) {
return HttpProblem.builder(problem)
.with("test", "test")
.build();
}
}
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.
You're right, @Unremovable
will work as well (I falsely assume removability is about runtime, but in fact it's about build time), I will add this to the example as possible option to use instead of @Startup
.
Nevertheless I don't think there's anything particularly wrong with @Startup
, which makes the bean unremovable (by implicitly declaring an observer method)
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.
Yeah, totally agree with that. I've just suggested another idea which could state the intention a little bit more explicitly.
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.
Maybe one last idea. How about adding an additional build-step which marks each @ProblemPostProcessor
as unremovable:
@BuildStep
UnremovableBeanBuildItem unremovableBeans() {
return UnremovableBeanBuildItem.beanTypes(ProblemPostProcessor.class);
}
By doing so, no additional annotation is required and the user doesn't need to be aware of any Quarkus internals.
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.
That looks neat indeed, a tiny bit of magic, but it looks like it's worth it. I'll look into it later.
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.
@@ -24,4 +25,9 @@ public void enableMetrics() { | |||
ExceptionMapperBase.postProcessorsRegistry.register(new MicroprofileMetricsCollector()); |
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.
Since a user should not call ExceptionMapperBase.postProcessorsRegistry.register
directly, maybe it makes sense reducing the visibility of that particular method.
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's not that you should not call it - it's not forbidden, but you're right - it could have been package private. As such change is breaking, we can do it in 4.0 earliest though.
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.
Ah ok, I thought your intention was not to offer this API publicly. But yeah, fine to me.
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 doesn't really matter now what my intention was, it would be api breaking change, and - if we want to be predictable and compliant with semver - we can't change it just like that
Makes it easy to implement custom
ProblemPostProcessor
by creating a regular CDI bean.Closes #301 (in combination with #311)