In fact builder pattern is combining mutable objects during creation with immutable result
1.1 --- a/samples/aserverinfo/nbproject/build-impl.xml Sat Jun 20 16:06:19 2009 +0200
1.2 +++ b/samples/aserverinfo/nbproject/build-impl.xml Tue Aug 25 11:32:10 2009 +0200
1.3 @@ -20,6 +20,13 @@
1.4
1.5 -->
1.6 <project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="aserverinfo-impl">
1.7 + <fail message="Please build using Ant 1.7.1 or higher.">
1.8 + <condition>
1.9 + <not>
1.10 + <antversion atleast="1.7.1"/>
1.11 + </not>
1.12 + </condition>
1.13 + </fail>
1.14 <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
1.15 <!--
1.16 ======================
1.17 @@ -152,10 +159,18 @@
1.18 <attribute default="${includes}" name="includes"/>
1.19 <attribute default="${excludes}" name="excludes"/>
1.20 <attribute default="${javac.debug}" name="debug"/>
1.21 - <attribute default="" name="sourcepath"/>
1.22 + <attribute default="${empty.dir}" name="sourcepath"/>
1.23 + <attribute default="${empty.dir}" name="gensrcdir"/>
1.24 <element name="customize" optional="true"/>
1.25 <sequential>
1.26 + <property location="${build.dir}/empty" name="empty.dir"/>
1.27 + <mkdir dir="${empty.dir}"/>
1.28 <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
1.29 + <src>
1.30 + <dirset dir="@{gensrcdir}" erroronmissingdir="false">
1.31 + <include name="*"/>
1.32 + </dirset>
1.33 + </src>
1.34 <classpath>
1.35 <path path="@{classpath}"/>
1.36 </classpath>
1.37 @@ -271,6 +286,8 @@
1.38 <java classname="@{classname}" dir="${work.dir}" fork="true">
1.39 <jvmarg line="${debug-args-line}"/>
1.40 <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
1.41 + <jvmarg value="-Dfile.encoding=${source.encoding}"/>
1.42 + <redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
1.43 <jvmarg line="${run.jvmargs}"/>
1.44 <classpath>
1.45 <path path="@{classpath}"/>
1.46 @@ -291,6 +308,8 @@
1.47 <element name="customize" optional="true"/>
1.48 <sequential>
1.49 <java classname="@{classname}" dir="${work.dir}" fork="true">
1.50 + <jvmarg value="-Dfile.encoding=${source.encoding}"/>
1.51 + <redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
1.52 <jvmarg line="${run.jvmargs}"/>
1.53 <classpath>
1.54 <path path="@{classpath}"/>
1.55 @@ -317,7 +336,23 @@
1.56 COMPILATION SECTION
1.57 ===================
1.58 -->
1.59 - <target depends="init" name="deps-jar" unless="no.deps"/>
1.60 + <target name="-deps-jar-init" unless="built-jar.properties">
1.61 + <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
1.62 + <delete file="${built-jar.properties}" quiet="true"/>
1.63 + </target>
1.64 + <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
1.65 + <mkdir dir="${build.dir}"/>
1.66 + <touch file="${built-jar.properties}" verbose="false"/>
1.67 + <property file="${built-jar.properties}" prefix="already.built.jar."/>
1.68 + <fail message="Cycle detected: aserverinfo was already built">
1.69 + <condition>
1.70 + <isset property="already.built.jar.${basedir}"/>
1.71 + </condition>
1.72 + </fail>
1.73 + <propertyfile file="${built-jar.properties}">
1.74 + <entry key="${basedir}" value=""/>
1.75 + </propertyfile>
1.76 + </target>
1.77 <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
1.78 <target depends="init" name="-check-automatic-build">
1.79 <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
1.80 @@ -333,10 +368,15 @@
1.81 <!-- You can override this target in the ../build.xml file. -->
1.82 </target>
1.83 <target if="do.depend.true" name="-compile-depend">
1.84 - <j2seproject3:depend/>
1.85 + <pathconvert property="build.generated.subdirs">
1.86 + <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
1.87 + <include name="*"/>
1.88 + </dirset>
1.89 + </pathconvert>
1.90 + <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
1.91 </target>
1.92 <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
1.93 - <j2seproject3:javac/>
1.94 + <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
1.95 <copy todir="${build.classes.dir}">
1.96 <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
1.97 </copy>
1.98 @@ -353,7 +393,7 @@
1.99 <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
1.100 <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
1.101 <j2seproject3:force-recompile/>
1.102 - <j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
1.103 + <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
1.104 </target>
1.105 <target name="-post-compile-single">
1.106 <!-- Empty placeholder for easier customization. -->
1.107 @@ -419,11 +459,29 @@
1.108 <property location="${dist.jar}" name="dist.jar.resolved"/>
1.109 <echo>java -jar "${dist.jar.resolved}"</echo>
1.110 </target>
1.111 + <target depends="init,compile,-pre-pre-jar,-pre-jar" if="libs.CopyLibs.classpath" name="-do-jar-with-libraries-without-manifest" unless="manifest.available+main.class">
1.112 + <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
1.113 + <pathconvert property="run.classpath.without.build.classes.dir">
1.114 + <path path="${run.classpath}"/>
1.115 + <map from="${build.classes.dir.resolved}" to=""/>
1.116 + </pathconvert>
1.117 + <pathconvert pathsep=" " property="jar.classpath">
1.118 + <path path="${run.classpath.without.build.classes.dir}"/>
1.119 + <chainedmapper>
1.120 + <flattenmapper/>
1.121 + <globmapper from="*" to="lib/*"/>
1.122 + </chainedmapper>
1.123 + </pathconvert>
1.124 + <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
1.125 + <copylibs compress="${jar.compress}" jarfile="${dist.jar}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
1.126 + <fileset dir="${build.classes.dir}"/>
1.127 + </copylibs>
1.128 + </target>
1.129 <target name="-post-jar">
1.130 <!-- Empty placeholder for easier customization. -->
1.131 <!-- You can override this target in the ../build.xml file. -->
1.132 </target>
1.133 - <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
1.134 + <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-do-jar-with-libraries-without-manifest,-post-jar" description="Build JAR." name="jar"/>
1.135 <!--
1.136 =================
1.137 EXECUTION SECTION
1.138 @@ -502,6 +560,9 @@
1.139 <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
1.140 <filename name="**/*.java"/>
1.141 </fileset>
1.142 + <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
1.143 + <include name="**/*.java"/>
1.144 + </fileset>
1.145 </javadoc>
1.146 </target>
1.147 <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
1.148 @@ -563,7 +624,7 @@
1.149 <j2seproject3:junit testincludes="**/*Test.java"/>
1.150 </target>
1.151 <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
1.152 - <fail if="tests.failed">Some tests failed; see details above.</fail>
1.153 + <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
1.154 </target>
1.155 <target depends="init" if="have.tests" name="test-report"/>
1.156 <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
1.157 @@ -576,7 +637,7 @@
1.158 <j2seproject3:junit excludes="" includes="${test.includes}"/>
1.159 </target>
1.160 <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
1.161 - <fail if="tests.failed">Some tests failed; see details above.</fail>
1.162 + <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
1.163 </target>
1.164 <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
1.165 <!--
1.166 @@ -642,7 +703,23 @@
1.167 CLEANUP SECTION
1.168 ===============
1.169 -->
1.170 - <target depends="init" name="deps-clean" unless="no.deps"/>
1.171 + <target name="-deps-clean-init" unless="built-clean.properties">
1.172 + <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
1.173 + <delete file="${built-clean.properties}" quiet="true"/>
1.174 + </target>
1.175 + <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
1.176 + <mkdir dir="${build.dir}"/>
1.177 + <touch file="${built-clean.properties}" verbose="false"/>
1.178 + <property file="${built-clean.properties}" prefix="already.built.clean."/>
1.179 + <fail message="Cycle detected: aserverinfo was already built">
1.180 + <condition>
1.181 + <isset property="already.built.clean.${basedir}"/>
1.182 + </condition>
1.183 + </fail>
1.184 + <propertyfile file="${built-clean.properties}">
1.185 + <entry key="${basedir}" value=""/>
1.186 + </propertyfile>
1.187 + </target>
1.188 <target depends="init" name="-do-clean">
1.189 <delete dir="${build.dir}"/>
1.190 <delete dir="${dist.dir}"/>
1.191 @@ -652,4 +729,20 @@
1.192 <!-- You can override this target in the ../build.xml file. -->
1.193 </target>
1.194 <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
1.195 + <target name="-check-call-dep">
1.196 + <property file="${call.built.properties}" prefix="already.built."/>
1.197 + <condition property="should.call.dep">
1.198 + <not>
1.199 + <isset property="already.built.${call.subproject}"/>
1.200 + </not>
1.201 + </condition>
1.202 + </target>
1.203 + <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
1.204 + <ant antfile="${call.script}" inheritall="false" target="${call.target}">
1.205 + <propertyset>
1.206 + <propertyref prefix="transfer."/>
1.207 + <mapper from="transfer.*" to="*" type="glob"/>
1.208 + </propertyset>
1.209 + </ant>
1.210 + </target>
1.211 </project>
2.1 --- a/samples/aserverinfo/nbproject/genfiles.properties Sat Jun 20 16:06:19 2009 +0200
2.2 +++ b/samples/aserverinfo/nbproject/genfiles.properties Tue Aug 25 11:32:10 2009 +0200
2.3 @@ -4,5 +4,5 @@
2.4 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
2.5 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
2.6 nbproject/build-impl.xml.data.CRC32=c82747ea
2.7 -nbproject/build-impl.xml.script.CRC32=1033418a
2.8 -nbproject/build-impl.xml.stylesheet.CRC32=84d9cdb5
2.9 +nbproject/build-impl.xml.script.CRC32=c7c23170
2.10 +nbproject/build-impl.xml.stylesheet.CRC32=29e56e74@1.29.0.45
3.1 --- a/samples/aserverinfo/nbproject/project.properties Sat Jun 20 16:06:19 2009 +0200
3.2 +++ b/samples/aserverinfo/nbproject/project.properties Tue Aug 25 11:32:10 2009 +0200
3.3 @@ -3,6 +3,7 @@
3.4 # This directory is removed when the project is cleaned:
3.5 build.dir=build
3.6 build.generated.dir=${build.dir}/generated
3.7 +build.generated.sources.dir=${build.dir}/generated-sources
3.8 # Only compile against the classpath explicitly listed here:
3.9 build.sysclasspath=ignore
3.10 build.test.classes.dir=${build.dir}/test/classes
4.1 --- a/samples/aserverinfo/src/org/apidesign/aserverinfo/builder/ServerInfo.java Sat Jun 20 16:06:19 2009 +0200
4.2 +++ b/samples/aserverinfo/src/org/apidesign/aserverinfo/builder/ServerInfo.java Tue Aug 25 11:32:10 2009 +0200
4.3 @@ -6,7 +6,7 @@
4.4 import org.apidesign.aserverinfo.spi.URLProvider;
4.5
4.6 /**
4.7 - * Cumulative factory methods for the builder pattern
4.8 + * Mutable "setter" methods for the builder pattern.
4.9 *
4.10 * @author Jaroslav Tulach <jtulach@netbeans.org>
4.11 */
4.12 @@ -18,15 +18,21 @@
4.13 }
4.14
4.15 public final ServerInfo nameProvider(NameProvider np) {
4.16 - return new ServerInfo(np, this.url, this.reset, this.shutdown);
4.17 + this.name = np;
4.18 + return this;
4.19 }
4.20
4.21 public final ServerInfo urlProvider(URLProvider up) {
4.22 - return new ServerInfo(this.name, up, this.reset, this.shutdown);
4.23 + this.url = up;
4.24 + return this;
4.25 }
4.26 + // BEGIN: aserverinfo.builder.setter
4.27 public final ServerInfo reset(ResetHandler h) {
4.28 - return new ServerInfo(this.name, this.url, h, this.shutdown);
4.29 + this.reset = h;
4.30 + return this;
4.31 }
4.32 + // END: aserverinfo.builder.setter
4.33 +
4.34 /** All one needs to do when there is a need to add new
4.35 * style of creation is to add new method for a builder.
4.36 * @param handler
4.37 @@ -34,7 +40,8 @@
4.38 * @since 2.0
4.39 */
4.40 public final ServerInfo shutdown(ShutdownHandler handler) {
4.41 - return new ServerInfo(this.name, this.url, this.reset, handler);
4.42 + this.shutdown = handler;
4.43 + return this;
4.44 }
4.45
4.46 /** Creates the server connector based on current values in the
4.47 @@ -46,10 +53,10 @@
4.48 }
4.49 // FINISH: aserverinfo.builder.factory
4.50
4.51 - private final NameProvider name;
4.52 - private final URLProvider url;
4.53 - private final ResetHandler reset;
4.54 - private final ShutdownHandler shutdown;
4.55 + private NameProvider name;
4.56 + private URLProvider url;
4.57 + private ResetHandler reset;
4.58 + private ShutdownHandler shutdown;
4.59
4.60 private ServerInfo(
4.61 NameProvider name, URLProvider url,
5.1 --- a/samples/aserverinfo/test/org/apidesign/aserverinfo/test/BuilderFactoryTest.java Sat Jun 20 16:06:19 2009 +0200
5.2 +++ b/samples/aserverinfo/test/org/apidesign/aserverinfo/test/BuilderFactoryTest.java Tue Aug 25 11:32:10 2009 +0200
5.3 @@ -32,16 +32,16 @@
5.4 NameProvider np = p;
5.5 URLProvider up = p;
5.6 ResetHandler res = p;
5.7 - ServerConnector inf;
5.8 + ServerConnector connection;
5.9
5.10 // BEGIN: ServerConnector.builder.creation
5.11 - inf = ServerInfo.empty()
5.12 + connection = ServerInfo.empty()
5.13 .nameProvider(np).urlProvider(up).reset(res).connect();
5.14 // END: ServerConnector.builder.creation
5.15
5.16 - assertEquals("API Design Server", inf.getName());
5.17 - assertEquals("http://www.apidesign.org", inf.getURL().toExternalForm());
5.18 - inf.reset();
5.19 + assertEquals("API Design Server", connection.getName());
5.20 + assertEquals("http://www.apidesign.org", connection.getURL().toExternalForm());
5.21 + connection.reset();
5.22 assertEquals("Once reset", 1, p.resets);
5.23
5.24 }
5.25 @@ -49,19 +49,19 @@
5.26 @Test
5.27 public void showVerboseUseOfBuilder() throws Exception {
5.28 Prov prov = new Prov();
5.29 - ServerConnector info;
5.30 + ServerConnector connection;
5.31
5.32 // BEGIN: ServerConnector.builder.creation.verbose
5.33 ServerInfo empty = ServerInfo.empty();
5.34 ServerInfo name = empty.nameProvider(prov);
5.35 ServerInfo urlAndName = name.urlProvider(prov);
5.36 ServerInfo all = urlAndName.reset(prov);
5.37 - info = all.connect();
5.38 + connection = all.connect();
5.39 // END: ServerConnector.builder.creation.verbose
5.40
5.41 - assertEquals("API Design Server", info.getName());
5.42 - assertEquals("http://www.apidesign.org", info.getURL().toExternalForm());
5.43 - info.reset();
5.44 + assertEquals("API Design Server", connection.getName());
5.45 + assertEquals("http://www.apidesign.org", connection.getURL().toExternalForm());
5.46 + connection.reset();
5.47 assertEquals("Once reset", 1, prov.resets);
5.48
5.49 }