Open Rawi01 opened 2 years ago
Seems like we eliminate a ton of easily messed up boilerplate in trade for a low maintenance burden. Sounds like a good idea.
As for the name:
@lombok.extern.faces.JsfComponentProperties
@lombok.extern.jsf.JSFComponentProperties
Or some other combination sounds right. I'm guessing the first one is the better option (fits the DvdPlayer
style conventions of writing acronyms in java's CamelCase format, and you import from package javax.faces
, I think, so presumably faces
is more natural than jsf
on this one. But, you're clearly more familiar with the domain :)
Some questions:
public List<String> getProperty1() { .. return (List<String>) getStateHelper()....
? If it is, how do we deal with the ugly-cast, do we also add the @SuppressWarnings
? Given that it's all runtime glue, the generics do nothing, I assume. Should we leave the warning (but then, how would one get rid of it? @SuppressWarnings
on the field? @lombok.extern.faces.JsfComponentProperties.SuppressUnchecked
on the field?@FieldNameConstants
does, so that'd be nice if it is :)long property5 = System.currentTimeMillis()
- would you expect the get
command, when the statehelper doesn't have anything (so the default kicks in) to return the time as it is was when the class was loaded, or would you expect the get command to execute the expression (thus, that getProperty5()
returns the same thing System.currentTimeMillis()
would.fCell
to getFCell()
or does JSF expect getfCell()
)? See issue #2693 - if JSF explicitly fails unless we generate getfCell()
, or something in the chain fails no matter which way we go, we should probably make an exception here and generate what JSF needs even if it isn't compatible with with lombok's @Getter
would do (or if happiness is impossible with a field named fCell
, we should error out on the field and explain the problem).getStateHelper()
is coming from javax.faces.component.UIComponent
- Looks like any usage of this feature would necessarily require that you extend something. What should we do if the outer class doesn't extend anything - should we just silently add extends UIComponent
, or should we error out?getFamily()
and that constructor that invokes setRendererType
?SelectOneMenuBase
), lombok can make on getTitle
and setTitle
for you, but isn't going to be able to figure out that it should stick an @Override
on these?// *** GENERATED CODE - DO NOT EDIT ***
at the top of it, so somebody out there already wrote some code gen system for this problem already. Is whatever made this commonly used (in which case the need for this feature goes down, or at least the focus on marketing this feature goes up), or is it something internal (in which case the fact that JBoss saw the need to write a code generator for this stuff only highlights that lombok should add this feature)?handleAttribute
in addition to getStateHelper().put
, which I assume is some internal JBoss thing and not relevant for this code generation. But it does open the question: If you want additional behaviour to e.g. a set method, do we just say: Hey, then write the whole thing yourself; feel free to use the PropertyKeys.propName
enum value we made for yo uthough. Or do we say: No problem, we'll inject that put line for you / you can tag some method as 'please run this method, supplying the enum and the property, as part of a set
call? e.g. that this JBoss code could be replaced with:@lombok.extern.faces.JsfComponentProperties.SetterHelper
public setAccesskeyHelper(PropertyKeys key, String accesskey) {
handleAttribute(key.name(), accessKey);
}
Where lombok figures out what to do, per argument (you can have up to one argument of type PropertyKeys, and up to one argument of the key type, with any name and in any order).
@JsfComponentProperties
, I assume the best idea there is to just error out and refer to the feature page on projectlombok.org in the error message showing how to use it. Or should we just spell it out (make an inner class and annotate it. The fields of that class are turned into properties, the initializers on those fields are considered the default-generating expression). I guess there's no nice way to just make this feature 'tag your top level with @JsfComponent
, and we'll take care of the rest. Seems a bit crass to scan for an inner class whose name matches the pattern xKeys
. Then again, tagging in inner class with an annotation which then results in lombok generating a ton of stuff in its enclosing class is also slightly weird. As this is an extern
feature, weirdness is fine (We presume that the user knows the library and its associated patterns well, for extern
features).I think satisfactory answers are available for all these questions, and armed with those, the feature seems good to go!
Is there really a convention to use CamelCase for acronyms? What about URLConnection
?
faces
is most likely the better name, there is already is a set of @Faces...
annotations so I think @lombok.extern.faces.FacesComponentProperties
is a better name.
@SuppressWarning
as soon as we detect the generic.java.beans.Introspector.decapitalize
@Override
is only a marker I think we can simply ignore that.Is there really a convention to use CamelCase for acronyms?
Yes, adopted by amongst others Oracle/team OpenJDK and google.
What about
URLConnection
?
Predates the convention. Same for URL
and URI
.
See:
HttpURLConnection
which mixes conventions. It partly has to (HTTPURLConnection
looks real bizarre), but it also serves as a nice objective example: DVDPlayer
is not just subjectively the wrong choice (as in, 'it is not (any longer) the official convention). It is in fact objectively the wrong choice. No style guide needed. Auto-complete systems based on first-letter-of-each-camelcased-word, such as most IDE's 'open type' dialogs, also don't really know what to do with DVDPlayer
(it's not found if you type DP
), whereas DvdPlayer
is handled just fine.GpsVersion
, not GPSVersion
).
lombok.extern.faces.FacesComponentProperties
Works for me!
Yes, generics are possible. I think we can add a @SuppressWarning as soon as we detect the generic.
Yup, let's just flat out generate it if needed and not make it configurable. I don't foresee any point in wanting to e.g. not generate it. @SuppressWarnings
is a bit of a mess (the actual keys you can pass to it are severely underspecced, which has resulted in various tools interpreting @SW
annotations in different ways, and generally means we have to usually add "all"
to the pile, but, one way or another, we just need to figure out what @SuppressWarnings
line works for the maximal amount of common environments and generate it. But, yes, only if we detect generics.
Great question, I never used something else than a constant value.
My primary concern is that users of this feature will make an assumption about how it works and will consider their assumption so obvious that they'd be highly surprised if it worked differently than what they think it does. Except, there are non-trivial amounts of programmers with that idea making different assumptions. I'm not sure there's any solution there other than to just accept that some folks will get confused and a little angry that 'lombok made such a dumb choice', and all we get to do is pick which group gets angry. One way out is to only allow literally constant literals, and not even refs to constants (because we need resolution to know), but that feels needlessly restrictive.
Copying the initializer though... not so sure we can do that. Expressions can contain almost all syntax nodes, as new Object() { whatever you want here }.foo();
is a legal expression. Copying all that is impossible. We can move it, though. With some minor risk (we're moving nodes and therefore changing contexts, which may break stuff), but there are other places we already do this. We mostly operate on the assumption nobody would be silly enough to actually make that the default. I guess the call is: Just.. do something, whatever. Some folks won't like it, but the vast majority of the team its a constant value and its a moot point.
IIRC it is getfName because it uses
java.beans.Introspector.decapitalize
Okay, let's do exactly that and not make it configurable.
Adding the extends seems to be a little bit to much magic
Okay, that means the feature will error out and link to the docs if you put the annotation on a top-level typedef.
Describe the feature A JSF component usually uses an enum to list all its properties. For each of the enumerated properties there is a getter and a setter which refers to the state helper to store the value.
Real world example: https://github.com/primefaces/primefaces/blob/9f8f972a1a549759859f684b4c221436c0ed93e2/primefaces/src/main/java/org/primefaces/component/selectonemenu/SelectOneMenuBase.java
Writing all that by hand is quite annoying and error prone (It took me more than an hour to figure out that I missed to adjust one property key in my copy pasted setter).
I propose to add an annotation (e.g.
@JSFComponentProperties
) that can be added to inner classes. It transforms the whole class into an enum using the field names, uses the field types for getter and setter types and moves the initializer to the default value. Some special handling for primitive types without initializers is required.Example to generate the code above:
Describe the target audience JSF developers
Additional context Most of this should be quite easy, converting a class into an enum might be a little bit harder.