IMO the cleanup things are related to the concrete object for which an
exception is handeled, so it will probably be clearer to invoke these
things on the object that caused an exception.
General exception handlers that will interact with the UI or anything
else to publish messages or so and cleanup work that should be done
after publishing such messages are different things IMO. The cleanup
should have it's own position in the flow. Just think of exception
handlers that would mark exceptions as handeled, there has to be somehow
a mechanism to ensure that a specific method is called.
Back to the annotation validation.
BVal and CBAV are quite different, BVal acts at runtime and CBAV at
compile time.
Also CBAV validators have to be able to use javax.lang.model types to
make validations.
A constraint can be declared like,
@ValueConstraint(UniqueValueConstraintValidator.class)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueValueConstraint {
ConstraintScope scope();
String errorMessage() default "The given value has to unique within
the defined scope";
}
The ValueConstraint declares that this annotation will act on members of
annotations. The other option is a more general constraint,
@Constraint(ExceptionConstraintValidator.class)
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionConstraint {
Class<? extends Throwable>[] expectedExceptions() default {};
// When true, the types have to match exactly, otherwise the
concrete types may be subtypes of the declared ones
boolean strict() default false;
String errorMessage() default "The exceptions in the throws clause
of the method does not match the expected";
}
The validators for the constraints could also be bound somehow inverse
but for now i chose this way.
I thought of this concept first, when I was using JPA annotations and
got runtime errors because of a wrong configuration. Such pitfalls at
runtime could be avoided by using such constraints.
In addition to my explanations I would like to give you an insight into
my current implementations. You can play around and maybe something can
be useful for deltaspike! :)
Here the links to the sources:
http://blazebit.com/blaze/BlazeCommonUtil-0.1.2-sources.jar
http://blazebit.com/blaze/BlazeCBAV-0.1.2-sources.jar
Both maven projects, just import them, make a new project with a
dependency on BlazeCBAV and checkout ;)
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*
Am 15.06.2012 22:24, schrieb Jason Porter:
On Fri, Jun 15, 2012 at 2:00 PM, Christian Beikov<
christian.bei...@gmail.com> wrote:
Hello!
I had a lot to do in the last days, so sorry for letting you wait for so
long ;)
In the last days I rethought all the exception stuff and in the end I
implemented an interceptor that will just catch exceptions and delegate
them via deltaspike exception handling to an appropriate exception handling
method.
I also decided to decouple the UI Feedback from the actual catching as I
used it before. If you don't remember here an example:
@ExceptionHandler({
@ExceptionHandling(exception=**MyException.class,
message=Cal10NEnum.MY_MESSAGE)
})
public class Bean{...}
I had a lot of default messages already declared at exception class level
like:
@ExceptionMessage(Cal10NEnum.**MY_MESSAGE)
public class MyException extends Exception{...}
Now I declare the catching, probably simmilar to seam catch(but I haven't
checked how seam catch works), like this:
Seam Catch and DeltaSpike exception handling are essentially the same
thing, with some renaming.
@CatchHandler({
@CatchHandling(exception=**MyException.class)
})
public class Bean{...}
I am not sure if seam catch has the following feature, but I needed it to
make sure that the UI will stay consistent:
@CatchHandler(
cleanup="generalCleanup",
exception=Throwable.class, // is the default
exceptions= {
@CatchHandling(exception=**MyException.class, cleanup="myCleanup")
})
public class Bean{
@Cleanup("generalCleanup")
public void generalCleanup(){
// reset some variables
}
@Cleanup("myCleanup")
public void myCleanup(){
// reset some variables
}
}
I would think using an interface and passing the class instead of the
string would be better. Yes, it may mean a few more classes at the end of
the day, but they're easier to find and the separation is better than
having it all in one (the same?) class.
First of all, any exception will be passed to deltaspike by the
interceptor, but additionally the cleanup methods will be invoked if a
cleanup is declared at the appropriate handling level. This is very useful
IMO and should be considered to be added if seam catch will be ported.
It was already ported in v0.2. A cleanup idea is interesting, but I'm not
sure if it brings anything better to the table than having a method that
your exception handlers call when they're done, I'd have to think about it
some more.
In my last mail I told you I have a mechanism to make the string
"identifiers" for the annotations more or less "type safe", at least I will
generate compiler errors via Annotation Processing Tool when something is
wrong.
I have written something that I call "Constraint Based Annotation
Validation" or short CBAV. Mainly this is a set of commonly used
constraints for annotations and the constraints can be declared via
annotations. Here a quick example:
public @interface Cleanup {
/**
* The class wide unique name for a cleanup method which can be invoked
to
* do cleanup work.
*
* @return The class wide unique name for a cleanup method
*/
@UniqueValueConstraint(scope = ConstraintScope.CLASS, errorMessage =
"There must not be other cleanup methods with the same name")
String value() default "";
}
The UniqueValueConstraint will make sure, that the member "value" of
cleanup annotations will be unique within class scope, if it is not, the
given compiler error message will be printed out.
Annotationg the Cleanup annotation with,
@ReturnTypeConstraint(**expectedReturnType = void.class, errorMessage =
"Cleanup methods must have void return type!")
public @interface Cleanup{...}
will enforce "void" return type on methods annotated with the cleanup
annotation.
I have some more example ;)
@ExceptionConstraint(**errorMessage = "No exceptions are allowed to be in
the throws clause for cleanup methods")
This will enforce that no exceptions can be made on methods annotated with
cleanup.
@ParameterConstraint(**errorMessage = "Cleanup methods must not have
parameters")
And that one is hopefully clear.
This is just a short explanation of what can be done with this tool, it is
much more powerful, the referencing is probably the most interesting
feature. Consider the following on the cleanup member of CatchHandler or
CatchHandling.
@ReferenceValueConstraint(**referencedAnnotationClass = Cleanup.class,
nullable = true, errorMessage = "There is no method annotated with the
cleanup annotation that has the specified name", scope =
ConstraintScope.CLASS)
String cleanup() default "";
Sounds to me like your constraints might be able to be implemented via Bean
Validation. It's worth a look anyway, if not, then it would be something
worth proposing to the EG.
This will make sure, that if a cleanup is set for a CatchHandler or
CatchHandling, that it muss exist within the class scope.
What do you think about that? Has that already been implemented by someone
and I just did't find anything on the internet or is this even so stunning
that I should try to standardize that within the JCP? ;)
[snip]