Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Configuration: Move static methods to ConfigUtil. Add documentation. #5292

Merged
merged 1 commit into from
Mar 27, 2018

Conversation

davidgraeff
Copy link
Contributor

@davidgraeff davidgraeff commented Mar 21, 2018

Signed-off-by: David Graeff david.graeff@web.de

@davidgraeff davidgraeff force-pushed the configutils branch 3 times, most recently from 17ebc58 to e93ffe0 Compare March 21, 2018 16:04
Copy link
Contributor

@htreu htreu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the overall refactoring but I'm not sure about the new @RequiredField and @UseKey annotations: They seem not to solve a real problem we face right now. Services which are not fully configured should already log their problems and will probably not work. Using fields with different names then their counterpart in the config description is also unlikely. wdyt?

public void modified(Map<String, Object> properties) {
// Print changed values
MagicServiceConfig config = new Configuration(properties).as(MagicServiceConfig.class);
List<Field> l = ConfigUtil.getAllFields(MagicServiceConfig.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of exposing the reflection based method getAllFields you could give a toString to MagicServiceConfig.

Copy link
Contributor Author

@davidgraeff davidgraeff Mar 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. Regarding the annotations: I actually introducted UseKey because the configuration key of one field in MagicServiceConfig where it's used, is unfortunately called "boolean", like the Java keyword.

I'm honestly a big fan of this property-map to class object mapping, partly because I do not find that powerful reflection API in many other languages. However I'd like to see this as a default way of handling service configuration and it should work in every case.

So we either need this UseKey annotation or we need to forbid certain configuration key names (Java language keywords).

@htreu
Copy link
Contributor

htreu commented Mar 21, 2018

For the time being I suggest to have the refactoring (and magic extension) only.

@davidgraeff
Copy link
Contributor Author

Agreed. I'll open another issue for discussion. I'll rename the magic bindings configuration name from boolean to "bool".

@davidgraeff
Copy link
Contributor Author

@htreu Done

@davidgraeff
Copy link
Contributor Author

And I have added an issue for the annotations #5300.

Copy link
Contributor

@htreu htreu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reduce visibility to private on ConfigUtil#getAllFields.
Others are only cosmetics.

* @param clazz The class
* @return A list of Field objects
*/
public static List<Field> getAllFields(Class<?> clazz) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make this private again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it would be nice to have the public API on top and the supporting private methods at the bottom of the class.

Copy link
Contributor Author

@davidgraeff davidgraeff Mar 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I usually would do that, but in this case all private/public fields and methods of the ConfigUtil class are widely mixed. If I sort them now, it would be a hard job reviewing. Should be done in another PR, if that's ok.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, thats a pity.
But then please order at least the refactored code, so that public comes first, private comes last. And please make #getAllFields private.


@Modified
public void modified(Map<String, Object> properties) {
MagicServiceConfig config = new Configuration(properties).as(MagicServiceConfig.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you introduced the new ConfigUtil#as method you can directly use it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be the only place of all services where it would be different. I'd like to wait for the discussion and outcome of #5300, if that is ok for you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed.

@davidgraeff
Copy link
Contributor Author

@htreu done

@davidgraeff
Copy link
Contributor Author

davidgraeff commented Mar 22, 2018

I have sorted depending on public/private methods now. But did two more things as well:

  • Added a nullable to this signature: normalizeType(Object value, @Nullable ConfigDescriptionParameter configDescriptionParameter).
  • Deprecated normalizeType(Object value)

@htreu
Copy link
Contributor

htreu commented Mar 22, 2018

Deprecated normalizeType(Object value)

Why? Everything just looked so good ;-)

@davidgraeff
Copy link
Contributor Author

Haha yes I know. Trouble maker /me :D
Let me explain my intention. Think of what normalizeTypes actually does: It converts all number types to BigDecimal and all collection types to Lists. Usually it would consider the configuration specification for the correct conversion. If this is not provided, it does this only on a best-effort approach.

The consumer of the API should clearly realize that he is using an API that only works best-effort and is used in a way that it originally was not intended to be used. The one argument only method hides this fact and the best way to realize the API intention is by the mandatory second argument ConfigDescriptionParameter.

@htreu
Copy link
Contributor

htreu commented Mar 22, 2018

Yes, I can follow your intention. Please revert the deprecation here so we can merge the refactoring. Lets discuss this new aspect on a separate PR where others can join the discussion. I don't want to blow this one up unnecessarily. Thanks :-)

@triller-telekom triller-telekom mentioned this pull request Mar 22, 2018
* @return The configuration holder object. All fields that matched a configuration option are set. If a required
* field is not set, null is returned.
*/
public static <T> @Nullable T as(Map<String, Object> properties, Class<T> configurationClass) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any particular reasons why this method must/should be exposed as API? I'd rather have expected to see in in a class within an internal package. In that way the Configuration class can use it and everybody else can do a new Configuration(Map).as(Class) if needed. What did I miss?

Copy link
Contributor Author

@davidgraeff davidgraeff Mar 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SJKA I tried to explain this in the PR message :)
new Configuration(Map).as(Class) does more than we need for service configuration objects. It "normalizes" values, which basically means all numbers -> BigDecimal, Collections -> Lists.

But the ConfigUtils.as method is way smarter, because it converts the types based on the field type. So yes, it makes sense to have it public API and use ConfigUtils.as within services.

If #5300 gets realized, the as() method might move to another package though. Maybe it should be marked as deprecated so that nobody starts to use it before this is discussed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to explain this in the PR message

If I didn't get that from your explanation, how should a user of the API figure that out? That is pretty surprising.

Another thing worth mentioning is that static utility methods only got us into trouble, both on testing/mocking side as well as with respect to evolving the APIs. We have been working in the past on getting rid of several such static helper methods and that always was painful on some end. Therefore I'd like to object to adding yet another one.

Maybe it should be marked as deprecated so that nobody starts to use it before this is discussed.

I don't know which "as" method you mean:

  • Configuration.as(...) must stay where it is, that cannot be moved anymore.
  • ConfigUtil.as.(...) must not be introduced publicly if we already suspect it will have to move. Why does it have to be public then if nobody should start using it?

@davidgraeff
Copy link
Contributor Author

It's hard to mock static methods true.

And yes documentation of this class is not very rich. The pr addresses some methos.

Please tell me how to proceed here. The mqtt stuff is once again ready and API changes of this pr are a requirement for my other PRs. The "as" method does not need to be moved in this PR, but it leads to inefficient code if it is not addressed. (Double type conversion of config values)

@htreu
Copy link
Contributor

htreu commented Mar 27, 2018

@davidgraeff, @SJKA to get this one finally approved I suggest to provide the APIs just as they are available now. Please refactor the public static as() method into some internal package. This gives us room for discussion and the rest of MQTT can finally move on.

* getAllFields, as methods moved from Configuration to internal ConfigMapper
* Add String->BigDecimal conversion in ConfigMapper.as
* Add configuration holder object to MagicService of the magic binding to see if the mapping works for all kind of configuration values.
* Sort ConfigUtils: public first.

Signed-off-by: David Graeff <david.graeff@web.de>
@davidgraeff
Copy link
Contributor Author

@htreu, @SJKA Done

Copy link
Contributor

@htreu htreu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thanks!

@htreu htreu merged commit 9bf79ed into eclipse-archived:master Mar 27, 2018
@htreu
Copy link
Contributor

htreu commented Mar 28, 2018

@davidgraeff Travis fails due to missing author-tag & JavaDoc on the new ConfigMapper. Please add this asap. Thanks :-)

@htreu
Copy link
Contributor

htreu commented Mar 28, 2018

Never mind, fixed it with #5320.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants