Skip to content
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

Add parameter to bypass setters #398

Closed
enedzvetsky opened this issue Mar 20, 2020 · 8 comments
Closed

Add parameter to bypass setters #398

enedzvetsky opened this issue Mar 20, 2020 · 8 comments
Labels
Milestone

Comments

@enedzvetsky
Copy link

Enhancement #388 breaks compatibility with previous versions.

Unfortunately, sometimes people add to setters business logic and this business logic doesn't support random data from easy-random.

Please add an additional setting to EasyRandomParameters like 'useSettersIfExist'.

@PYangDizzle
Copy link

I just stumbled here.

Agreed on the backward compatibility issue that using setters should be the optional behavior instead of a default behavior.
I'm just curious with one thing. If the setter doesn't support some value (i.e. 123) and easy-random happened to set the field to the value, would that be valid and wanted behavior?

@fmbenhassine
Copy link
Member

fmbenhassine commented Mar 24, 2020

Thank you for opening this issue. I did not expect that to be a breaking change, apologies for that. I can add the requested option and ship a new version asap.

However, I do not agree with the following:

using setters should be the optional behavior instead of a default behavior

As a class designer, if I want to enforce some rules while setting fields to make sure my object's internal state is valid, I do not want Easy Random or any other library to bypass my setter by default and create invalid instances of my class, unless I explicitly tell the library to do so (See example in #400).

Please add an additional setting to EasyRandomParameters like 'useSettersIfExist'.

So IMO the option should rather tell the library to ignore/bypass setters instead of using them if they exist. Do you agree?

As we all know, naming is hard.. I suggest bypassSetters which I think is a good name as it is explicit. If you have a better name, I'm open for suggestions. Otherwise, I can proceed and add the option asap.

@PYangDizzle
Copy link

I completely agree with your philosophy. It's actually why I started looking for an existing random instance library.

My point was focused solely on backward-compatibility because easy-random is already bypassing the setters by using the reflected Field objects. I think this is the concern the original poster raises.

bypassSetters sound good enough, to me.

fmbenhassine added a commit that referenced this issue Mar 25, 2020
@fmbenhassine
Copy link
Member

fmbenhassine commented Mar 25, 2020

@PYangDizzle thank you for your feedback.

My point was focused solely on backward-compatibility because easy-random is already bypassing the setters by using the reflected Field objects

Indeed, that's a bug, see #400. Easy Random ignores the setter invocation failure and proceeds with reflection anyway (which should not be the case). But that's fixed now.

I added a new parameter called bypassSetters as discussed. It could be tested in the 4.3.0-SNAPSHOT version. So to sum up:

  • If bypassSetters is set, setters will not be called and fields will be set using reflection directly.
  • Otherwise (the default), Easy Random will first try to call the setter if present (to respect the intention of the class designer). If the setter invocation succeeds, that means the random value is valid according to the setter's logic and ER will set the field and proceed with next fields. If the setter invocation fails (like when generating a random invalid value), it will throw an exception (unless ignoreRandomizationErrors is set). If there is no setter or the setter cannot be accessed or any other introspection failure happens, ER will fallback to reflection as well.

Of course, this will be documented in the wiki.

@enedzvetsky wdyt? Looking forward for your feedback since you requested this feature. Nothing is final in the current snapshot, we can always rename the parameter or change the behaviour if you have a better suggestion.

@PYangDizzle
Copy link

@benas
Since you are committed to using setters as a default, I have some questions.

  • If there's no setter for a field, should it be set by easy-random? Doesn't it mean it's set by a setter for a different field for the purpose of counting, status, etc.? Do we want to override what may have been set by other setters?
  • I'm not sure what you mean by setter cannot be accessed. If it's non-public, can't it be overridden? It it can't, shouldn't that be considered an error?
  • I just feel like easy-random should never fall back to reflecting the fields since Java Beans should have setters.

These points are difficult to address because they will deviate easy-random from the current behavior too much. I just want to ask the questions.

@fmbenhassine
Copy link
Member

  • If there's no setter for a field, should it be set by easy-random? Doesn't it mean it's set by a setter for a different field for the purpose of counting, status, etc.? Do we want to override what may have been set by other setters?

Yes, if there is no setter, the field should be randomized by default, unless it is excluded by the user. You can use custom randomizers to override the behaviour.

  • I'm not sure what you mean by setter cannot be accessed. If it's non-public, can't it be overridden? It it can't, shouldn't that be considered an error?

Yes, I mean everything that might yield a IntrospectionException or an IllegalAccessException. I don't see why this should be considered as an error. The idea is to make the behaviour regarding setters consistent with the one related to constructors: by default, if the type does not provide a default constructor, ER will fallback to objenesis and create the type anyway (see the wiki here). Same for setters, ER will try to introspect the type for a setter, and if it is not able to do it, it will use the force 😄 Of course, if this is not wanted, the field can be excluded or a custom randomizer can be used.

  • I just feel like easy-random should never fall back to reflecting the fields since Java Beans should have setters.

Easy Random was initially designed to randomize Java Beans only which by definition provide a setter for each property. This design decision turned out to be restrictive and many people started quickly asking to relax things and make it possible to randomize types that do not provide setters. If we remove the fallback to reflection when no setter is present, that would be a breaking change for all these people.. in addition to making the scope of the library very limited.

Hopefully I answered all your questions.

@enedzvetsky
Copy link
Author

enedzvetsky commented Mar 26, 2020

@benas Looks good. Setters should be used by default since we work with POJO objects.
Name 'bypassSetters' is also ok if we use setters by default.
Probably we need to add more flexibility and add setting to setup different behavior for different entities.

@fmbenhassine
Copy link
Member

Setters should be used by default since we work with POJO objects.
Name 'bypassSetters' is also ok if we use setters by default.

Perfect! we agree on the default behaviour and on the parameter name.

Thank you for your feedback.

@fmbenhassine fmbenhassine changed the title Add additional setting to disable "Set fields by calling setters if present before using reflection" Add parameter to bypass setters Mar 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants