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

Chained builders for list members #42

Open
dbirch-cognitoiq opened this issue Jan 8, 2019 · 4 comments
Open

Chained builders for list members #42

dbirch-cognitoiq opened this issue Jan 8, 2019 · 4 comments

Comments

@dbirch-cognitoiq
Copy link

dbirch-cognitoiq commented Jan 8, 2019

I have recently updated to the latest version of the plugin to allow me to use the new functionality in #33 for fluent builders. I am really enjoying using it and it has saved me so much work in manually creating the builders and data objects to interact with our API.

This has been really helpful for chaining builders together and allowing me to take an existing object, convert it to a builder, modify it then build back to an immutable object.

I am however seeing issues for members which are lists. The main XML schema we use has a lot of these and unfortunately, the chained builders don't seem to work, only the standard withA(A) type methods and addA() methods which will initialise a builder to add a new object to the list.

The issue comes when I want to take an existing data object and update one of the objects in the list with new values. The current methods provided do not give me any good way to chain my way through and modify these existing objects in the list using the newCopyBuilder() of the parent object without having to manually create builders for each of the list objects and provide them back to the builder without any of the chaining that has been so useful.

Is there any way to extend the current chained builders to allow us to use list-based members in the same way that single ones do, whereby we could call withA() and it initialises a builder for each member of the list and provide a way to access these builders using the standard chained builder idioms?

I'm guessing that this would involve some custom list implementation which would allow a List of builders to implement Builder and provide the .end() method to allow it to chain back to the parent object.

Hope this makes sense, can give a more concrete example if not.

@dbirch-cognitoiq
Copy link
Author

Pondered this one overnight and I think some kind of BuilderList class might do the trick. This would implement Buildable and provide the chained end() method and a reference to the parent builder.

This should allow the following kind of syntax:

builder.withListMember()
.get(0).withMember(memberValue).withOther(otherValue).end()
.get(1).withMember(nextValue).end()
.end()
.withB(bValue)
.end()

Not overly keen on the explicit gets, I'm wondering with the java 8 support whether there could be a get method which takes a function to allow getting an item from the list conditionally?

e.g

builder.withListMember()
.getWhere(item -> item.getMember().equals("value")).withMember("newValue").end()

This would have the overhead of converting the builder into an object, but the current case requires doing this same overhead manually so I don't see it would be a massive issue.

Any thoughts?

@mklemm
Copy link
Owner

mklemm commented Jan 9, 2019 via email

@dbirch-cognitoiq
Copy link
Author

dbirch-cognitoiq commented Jan 9, 2019

Thanks for the response, it's appreciated :)

I initially misunderstood what you mean about the getters, but as I understand it now it would allow users to get the values of the properties currently stored by the builder, my worry is that accidentally calling one of these methods would stop the builder from chaining and would only really be useful within the functions that I've suggested.

Streaming the list values also sounds like it could be an idea. My worry was that a stream().filter(function).findFirst().orElseThrow() might be a little verbose for a fluent chained builder and that wrapping up this code within a utility method might make the builders more readable.

More than happy to help out with the implementation of this if you'd like once you've had a think about how you would like it implemented. I'm quite keen to get this functionality soonish before my team add all sorts of horrible workarounds to our codebase to work around this feature not being present :D

@pmihnea
Copy link

pmihnea commented Dec 1, 2023

Hi everybody,
I also had the need to update a builder, especially the existing builders of a collection property. There was no way to iterate over those and update them.
Although the BuilderList idea presented earlier looks very appealing as it supports the fluent builder approach I found that for this operation of updating an exiting builder I do not needed it.
I mostly need to traverse the builder in depth until I find the right sub-builder and to update some property. I do not need to be able to 'end' that builder and jump back to the parent to update it. If I need to update the parent then I can do it during the traversal.
So I realized that adding a getter for each builder field would solve my problem. With these getters I can read all existing builder fields, both the simple or the collection ones, which allows me to implement any kind of search/filter and update builder operation.
I implemented the generation of those getters under a new fluent-builder/getters option which is off by default.
Please have a look on this pull request and let me know if it is ok:
#73

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

No branches or pull requests

3 participants