Yes, for a programmatic configuration builders would be better. Unless, of course, we came up with some other way for programmatic configurations to interact with plugins. For example, a method like
T createPlugin(PluginType type, Map<String, Object> map) might make more sense. Then it wouldn’t much matter whether we are using builders or the factory pattern. Ralph On Jun 16, 2014, at 8:12 AM, Matt Sicker <boa...@gmail.com> wrote: > Programmatic configuration is feature in that list of issues Ralph mentioned. > I don't see any good way to do that without using the fluent builder pattern > as that's how programmatic configuration APIs are usually done. The other > ways are usually things like closures/lambdas, but that would require Java > 1.8+ to work. Groovy supports closures which is what makes Gradle so much > less verbose, so that, too, is an alternative way to support builders. > > I guess the important thing to consider here is that the builders aren't for > _plugins_, but are for plugin _configurations_. That makes me think that the > factory methods (whether they be private or public) should be far more > generic such as accepting a PluginConfiguration object (each specific to the > plugin) or a generic Map<String, Object> that also makes it a lot simpler to > pass in plugin attributes. > > > On 16 June 2014 10:05, Gary Gregory <garydgreg...@gmail.com> wrote: > Right, so they are not part of the public API, unless we consider > programmatic configuration (not from a file). > > Gary > > > On Mon, Jun 16, 2014 at 10:56 AM, Remko Popma <remko.po...@gmail.com> wrote: > Paul this is about the plugin factory methods that are called by the > PluginManager to turn a configuration text file into an object hierarchy with > Loggers, Appenders, etc. > It would be very rare for client code to call these methods directly. Which > is why they are primarily called from JUnit tests. > > > On Mon, Jun 16, 2014 at 11:45 PM, Paul Benedict <pbened...@apache.org> wrote: > If this API is primarily for unit tests, then I don't care as much. I thought > this was Public API. When it comes to Public API, I prefer to make it as > friendly-to-read and maintainable as possible. > > > Cheers, > Paul > > > On Mon, Jun 16, 2014 at 9:42 AM, Remko Popma <remko.po...@gmail.com> wrote: > About the validation, wasn't the argument that some of the current JUnit > tests look like this? > FileAppender.createAppender("true", "true", "true", "true", "true", "true", > "true", "4096", null, null, "false", null, null); > > So, null is fine here for at least four arguments. > So it is definitely possible to forget to call the builder.setValue(value) > method for those arguments > - which is fine if your intention was to set null, but not if you forgot to > set some non-null value. > > The compiler validates that you have the right number of arguments for free. > It is not possible for builders to provide the same guarantee unless all > arguments must be non-null. > > About the readability - and as Ralph pointed out this is readability in JUnit > code primarily - there are a number of ways to accomplish that. > > > > On Mon, Jun 16, 2014 at 11:27 PM, Ralph Goers <ralph.go...@dslextreme.com> > wrote: > That is pretty much what Matt implemented. See the other arguments around > this, the primary one being that the factory methods are normally invoked > dynamically so you wouldn’t be looking at the code that calls them. They are > primarily called in the open in unit tests. > > Ralph > > On Jun 16, 2014, at 6:49 AM, Paul Benedict <pbened...@apache.org> wrote: > >> I don't know why the Spring link isn't working (try later) but this is how I >> think you guys can make the builder pattern better. Honestly, it's >> impossible to comprehend what the parameters mean just by looking at the >> code in the current form. >> >> Example returning a custom builder interface: >> FileAppender.builder() >> .setPropertyX(true) >> .setPropertyY(true) >> .setPropertyZ(4096) >> .setPropertyA(null) >> .create(); >> >> Paul >> >> >> >> Cheers, >> Paul >> >> >> On Mon, Jun 16, 2014 at 8:41 AM, Remko Popma <remko.po...@gmail.com> wrote: >> Matt, >> >> Ralph's argument (and I agree) was that we want only one way to do plugins, >> either with a factory method or with a builder. >> >> Currently only two plugins use the new builder: PatternLayout and HtmlLayout. >> So we can either revert these two back to use a factory method, or we can >> convert the remaining 147 uses of the factory method to builders. >> That last option would mean writing the builders for those plugins, and >> modifying all JUnit tests that currently use the factory methods. >> >> I agree with Ralph that converting all remaining 147 places to use builders >> would take up a lot of our time and energy for very little gain. >> >> Matt, you mentioned that you could live with factory methods if there was a >> better way to write JUnit tests than >> FileAppender.createAppender("true", "true", "true", "true", "true", "true", >> "true", "4096", null, null, "false", null, null); >> >> I believe I've demonstrated several ways in which such JUnit test code can >> be improved. >> Are you okay with removing the builders and reverting back to the factory >> methods? >> >> >> >> On Mon, Jun 16, 2014 at 10:23 PM, Matt Sicker <boa...@gmail.com> wrote: >> I'm unable to load that page for some reason, but yes, using a factory >> method as such is really not extensible. If the factory method took a Map or >> some sort of configuration object (which itself could use the fluent builder >> pattern), that would be less tightly coupled. >> >> Wouldn't it also make sense for the factory methods to be private or >> similar? That way they're only accessible through reflection. >> >> >> On Sunday, 15 June 2014, Paul Benedict <pbened...@apache.org> wrote: >> You don't want factory methods that take umpteen arguments. That's no way to >> make your builder extensible for future enhancements. Instead, you want a >> builder object that has a fluent API. >> >> http://docs.spring.io/spring/docs/3.2.8.RELEASE/javadoc-api/org/springframework/beans/factory/support/BeanDefinitionBuilder.html >> >> >> Cheers, >> Paul >> >> >> On Sun, Jun 15, 2014 at 10:04 PM, Ralph Goers <ralph.go...@dslextreme.com> >> wrote: >> Matt, >> >> The only objection I have to builders is that there should only be one way >> to configure plugins and I have neither the time or energy to convert all >> plugins from factories to builders. With 130+ open issues I think our time >> is better focused there instead of fixing something that already works. >> >> And, FWIW, the only place you will see createAppender coded like that is in >> unit tests and there are a bunch of ways to make that clearer. >> >> Ralph >> >> On Jun 15, 2014, at 7:19 PM, Matt Sicker <boa...@gmail.com> wrote: >> >>> I'm really against using factory methods due to language limitations in >>> Java. You can't specify default values, for one. Two, the more parameters a >>> factory takes, the crazier the method is. Seriously, tell me what this >>> method is specifying: >>> >>> FileAppender.createAppender("true", "true", "true", "true", "true", "true", >>> "true", "4096", null, null, "false", null, null); >>> >>> >>> On 15 June 2014 21:05, Remko Popma <remko.po...@gmail.com> wrote: >>> I'm fine with just the factory methods too. >>> >>> Sent from my iPhone >>> >>> On 2014/06/16, at 9:44, Scott Deboy <scott.de...@gmail.com> wrote: >>> >>>> +1 >>>> >>>> On Jun 15, 2014 4:05 PM, "Ralph Goers" <ralph.go...@dslextreme.com> wrote: >>>> Do we need the builders? As I said, I prefer only one way for creating >>>> plugins. >>>> >>>> Ralph >>>> >>>> On Jun 15, 2014, at 2:49 PM, Remko Popma <remko.po...@gmail.com> wrote: >>>> >>>>> I see. I agree that the original format is much nicer. >>>>> >>>>> Matt, do you think you can achieve this with the builders? >>>>> >>>>> Sent from my iPhone >>>>> >>>>> On 2014/06/16, at 1:29, Ralph Goers <ralph.go...@dslextreme.com> wrote: >>>>> >>>>>> While you improved some of the existing messages, you really didm’t >>>>>> address what I wanted fixed. The previous debug logs would have had >>>>>> messages similar to: >>>>>> >>>>>> Calling createLayout on class >>>>>> org.apache.logging.log4j.core.layout.PatternLayout for element >>>>>> PatternLayout with params(pattern="%d{HH:mm:ss.SSS} [%t] %-5level >>>>>> %logger{36} - %msg%n", >>>>>> Configuration(D:\rista\eclipsekws\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\log4j2.0-test\WEB-INF\classes\test-log4j.xml), >>>>>> null, charset="null", alwaysWriteExceptions="null") >>>>>> >>>>>> Calling createAppender on class >>>>>> org.apache.logging.log4j.core.appender.ConsoleAppender for element >>>>>> Console with params(PatternLayout(%d{HH:mm:ss.SSS} [%t] %-5level >>>>>> %logger{36} - %msg%n), null, target="SYSTEM_OUT", name="console", >>>>>> follow="null", ignoreExceptions="null") >>>>>> >>>>>> Calling createAppenderRef on class >>>>>> org.apache.logging.log4j.core.config.AppenderRef for element >>>>>> appender-ref with params(ref="console", level="null", null) >> >> >> -- >> Matt Sicker <boa...@gmail.com> >> >> > > > > > > > > -- > E-Mail: garydgreg...@gmail.com | ggreg...@apache.org > Java Persistence with Hibernate, Second Edition > JUnit in Action, Second Edition > Spring Batch in Action > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory > > > > -- > Matt Sicker <boa...@gmail.com>