Extending 15.28 to include toString() on an enum constant

Remi Forax forax at univ-mlv.fr
Mon Jul 9 06:39:42 UTC 2018


[this was sent to the amber-spec-comment]

Hi Daniel,

----- Mail original -----
> De: "Daniel Trebbien" <dtrebbien at gmail.com>
> À: "amber-spec-comments" <amber-spec-comments at openjdk.java.net>
> Envoyé: Lundi 9 Juillet 2018 02:43:00
> Objet: Extending 15.28 to include toString() on an enum constant

> One small idea I have for enhancing the Java language is to allow
> toString() on enum constants to be used in constant expressions, as long as
> toString()
> <https://docs.oracle.com/javase/10/docs/api/java/lang/Enum.html#toString()>
> is not overidden, or if it is, the implementation returns a constant
> expression.
>
> There are two use cases I have in mind for this:
>
> 1. When using the SLF4J logging library, if you want to embed the name of
> an enum constant in the log message, you should use parameterized logging
> to avoid incurring a wasted runtime string concatenation if logging at the
> specified level is disabled.  See SLF4J's FAQ for "What is the fastest way
> of (not) logging?":  https://www.slf4j.org/faq.html#logging_performance
> As an example of this in the wild, I submitted a pull request in which I
> converted a log statement involving an enum constant to parameterized
> logging:
> https://github.com/Netflix/eureka/commit/ad81a1140f351ec19165cb94d5aa668cfc08a932
> There are other cases where an SLF4J logger call involving an enum constant
> correctly used parameterized logging, but I am not able to find an example
> right now.

SLF4J should offer to have a lambda as parameter (as log4j2 does), parameterized logging solve the problem of the cost when not logging but at the cost of slowing down the logging when the logger logs because it has to do string interpolation.  

>
> Although using parameterized logging solves the performance issue, it is
> desirable to keep down the number of parameters to an SLF4J logger call
> because the SLF4J Logger interface
> <https://www.slf4j.org/apidocs/org/slf4j/Logger.html> has more efficient
> variants of the trace(), debug(), info(), warn(), and error() calls that
> take zero, exactly one, and exactly two parameters.  If a logger call
> passes at most two parameters, then the construction of an Object array to
> package the parameters into varargs is avoided.  Needing to "waste" a
> parameter slot on an enum constant is undesirable.
>
> 2.  When using Spring Security, it is possible to define an enum that lists
> the roles and other categories of permissions that are used by a Spring
> application.  For example:
>
> package com.myapp.security;
>
> import org.springframework.security.core.GrantedAuthority;
>
> public enum AppAuthority implements GrantedAuthority {
>
>    ROLE_USER,
>    ROLE_ADMINISTRATOR;
>
>    @Override
>    public String getAuthority() {
>        return toString();
>    }
> }
>
> When using the org.springframework.security.access.annotation.Secured
> <https://docs.spring.io/spring-security/site/docs/5.0.6.RELEASE/api/org/springframework/security/access/annotation/Secured.html>
> annotation to secure controllers or actions, it would be nice to be able to
> use an enum constant in the annotation's value, as in @Secured({
> ROLE_ADMINISTRATOR.toString() }); however, this is currently not valid Java
> code because ROLE_ADMINISTRATOR.toString() is not a constant expression.
> Instead, the name of the role must be duplicated:  @Secured({ "
> ROLE_ADMINISTRATER" }).  This is undesirable because it is error-prone and
> makes refactoring more difficult.  It is also more difficult to find usages
> of a particular authority.  If toString() on an enum constant were allowed
> within a constant expression, then finding usages of a particular authority
> would be a "Find Usages" operation in an IDE.

JEP 303 (http://openjdk.java.net/jeps/303) allows to build such kind of constants, i don't know if it works in the context of annotations but it's a nice use case.

The other solution is to allow any expressions in a annotation context and let the compiler emit a Constant_Dynamic that will be initialized with that expression, this solution has the advantage over the JEP 303 of not evaluating the expression by the compiler but at runtime by the VM, meaning that if there is a bug in toString() or in any calls inside of the expression, you do not have to re-compile the code. As a war story, a friend of mine has exactly the same issue with a Kotlin function which checks some credential and is marked inline there was a bug in it, so he rolls a security fix only to see that the bug was still appearing sometimes because he had to recompile all the codes that were using that function too.

regards,
Rémi


More information about the amber-spec-experts mailing list