diff options
-rw-r--r-- | buildScripts/website.ant.xml | 3 | ||||
-rw-r--r-- | doc/changelog.markdown | 2 | ||||
-rw-r--r-- | usage_examples/experimental/AccessorsExample_pre.jpage | 2 | ||||
-rw-r--r-- | usage_examples/experimental/ExtensionMethodExample_post.jpage | 20 | ||||
-rw-r--r-- | usage_examples/experimental/ExtensionMethodExample_pre.jpage | 23 | ||||
-rw-r--r-- | website/features/experimental/Accessors.html | 2 | ||||
-rw-r--r-- | website/features/experimental/ExtensionMethod.html | 109 | ||||
-rw-r--r-- | website/features/experimental/index.html | 2 |
8 files changed, 161 insertions, 2 deletions
diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml index 8397185a..0531129d 100644 --- a/buildScripts/website.ant.xml +++ b/buildScripts/website.ant.xml @@ -148,6 +148,9 @@ such as converting the changelog into HTML, and creating javadoc. <antcall target="-integrateSnippet"> <param name="transformationName" value="experimental/Accessors" /> </antcall> + <antcall target="-integrateSnippet"> + <param name="transformationName" value="experimental/ExtensionMethod" /> + </antcall> </target> <target name="-website-dist"> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index e59a43c7..ec79ead7 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,6 +2,8 @@ Lombok Changelog ---------------- ### v0.11.1 (EDGE) +* FEATURE: {Experimental} `@ExtensionMethod` is now available to add extensions to +any type in the form of static methods that take as first parameter an object of that type. [Documentation on @ExtensionMethod](http://projectlombok.org/features/experimental/ExtensionMethod.html) * ENHANCEMENT: Small performance enhancements in `equals` and `hashCode`. [Issue #366](http://code.google.com/p/projectlombok/issues/detail?id=366) * BUGFIX: Eclipse refactor script 'rename method arguments' should work more often with lombok-affected methods. * BUGFIX: Using 'val' in an enhanced for loop did not work if the iterable was a raw type. diff --git a/usage_examples/experimental/AccessorsExample_pre.jpage b/usage_examples/experimental/AccessorsExample_pre.jpage index ef063daa..f1591aba 100644 --- a/usage_examples/experimental/AccessorsExample_pre.jpage +++ b/usage_examples/experimental/AccessorsExample_pre.jpage @@ -1,4 +1,4 @@ -import lombok.Accessors; +import lombok.experimental.Accessors; import lombok.Getter; import lombok.Setter; diff --git a/usage_examples/experimental/ExtensionMethodExample_post.jpage b/usage_examples/experimental/ExtensionMethodExample_post.jpage new file mode 100644 index 00000000..72a838bd --- /dev/null +++ b/usage_examples/experimental/ExtensionMethodExample_post.jpage @@ -0,0 +1,20 @@ +public class ExtensionMethodExample { + public String test() { + int[] intArray = {5, 3, 8, 2}; + java.util.Arrays.sort(intArray); + + String iAmNull = null; + return Extensions.or(iAmNull, Extensions.toTitleCase("hELlO, WORlD!")); + } +} + +class Extensions { + public static <T> T or(T obj, T ifNull) { + return obj != null ? obj : ifNull; + } + + public static String toTitleCase(String in) { + if (in.isEmpty()) return in; + return "" + Character.toTitleCase(in.charAt(0)) + in.substring(1).toLowerCase(); + } +} diff --git a/usage_examples/experimental/ExtensionMethodExample_pre.jpage b/usage_examples/experimental/ExtensionMethodExample_pre.jpage new file mode 100644 index 00000000..26d0ee38 --- /dev/null +++ b/usage_examples/experimental/ExtensionMethodExample_pre.jpage @@ -0,0 +1,23 @@ +import lombok.experimental.ExtensionMethod; + +@ExtensionMethod({java.util.Arrays.class, Extensions.class}) +public class ExtensionMethodExample { + public String test() { + int[] intArray = {5, 3, 8, 2}; + intArray.sort(); + + String iAmNull = null; + return iAmNull.or("hELlO, WORlD!".toTitleCase()); + } +} + +class Extensions { + public static <T> T or(T obj, T ifNull) { + return obj != null ? obj : ifNull; + } + + public static String toTitleCase(String in) { + if (in.isEmpty()) return in; + return "" + Character.toTitleCase(in.charAt(0)) + in.substring(1).toLowerCase(); + } +} diff --git a/website/features/experimental/Accessors.html b/website/features/experimental/Accessors.html index 65b3c3b6..f3a7878f 100644 --- a/website/features/experimental/Accessors.html +++ b/website/features/experimental/Accessors.html @@ -84,7 +84,7 @@ </div> </div> <div class="footer"> - <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <span class="disabled">Next feature</span><br /> + <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br /> <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2012 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> </div> <div style="clear: both;"></div> diff --git a/website/features/experimental/ExtensionMethod.html b/website/features/experimental/ExtensionMethod.html new file mode 100644 index 00000000..773904bb --- /dev/null +++ b/website/features/experimental/ExtensionMethod.html @@ -0,0 +1,109 @@ +<!DOCTYPE html> +<html><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="stylesheet" type="text/css" href="../../logi/reset.css" /> + <link rel="stylesheet" type="text/css" href="../features.css" /> + <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" /> + <meta name="description" content="Spice up your java" /> + <title>EXPERIMENTAL - @ExtensionMethod</title> +</head><body><div id="pepper"> + <div class="minimumHeight"></div> + <div class="meat"> + <div class="header"><a href="../../index.html">Project Lombok</a></div> + <h1>@ExtensionMethod</h1> + <div class="byline">Annoying API? Fix it yourself: Add new methods to existing types!</div> + <div class="since"> + <h3>Since</h3> + <p> + @ExtensionMethod was introduced as experimental feature in lombok v0.11.2. + </p> + </div> + <div class="experimental"> + <h3>Experimental</h3> + <p> + Experimental because: + <ul> + <li>High-impact on code style</li> + <li>Really would like to ship with utility methods to expand common classes, but so far lombok doesn't have a good distribution method for such runtime dependencies</li> + <li>Affects quite a bit of eclipse, and auto-complete e.d. do not work yet in netbeans</li> + <li>Should @ExtensionMethod be legal on methods? Should it be legal on packages?</li> + </ul> + Current status: <em>positive</em> - Currently we feel this feature may move out of experimental status with no or minor changes soon. + </div> + <div class="overview"> + <h3>Overview</h3> + <p> + You can make a class containing a bunch of <code>public</code>, <code>static</code> methods which all take at least 1 + parameter. These methods will extend the type of the first parameter, as if they were instance methods, using the + <code>@ExtensionMethod</code> feature. + </p> + </p><p> + For example, if you create <code>public static String toTitleCase(String in) { ... }</code>, you can use the + <code>@ExtensionMethod</code> feature to make it look like the <code>java.lang.String</code> class has a method named + <code>toTitleCase</code>, which has no arguments. The first argument of the static method fills the role of <code>this</code> + in instance methods. + </p><p> + All methods that are <code>public</code>, <code>static</code>, and have at least 1 argument whose type is not primitive, are + considered extension methods, and each will be injected into the namespace of the type of the first parameter as if they were + instance methods. As in the above example, a call that looks like: <code>foo.toTitleCase()</code> is replaced with + <code>ClassContainingYourExtensionMethod.toTitleCase(foo);</code>. Note that it is actually not an instant + <code>NullPointerException</code> if <code>foo</code> is null - it is passed like any other parameter. + </p><p> + You can pass any number of classes to the <code>@ExtensionMethod</code> annotation; they will all be searched for + extension methods. These extension methods apply for any code that is in the annotated class. + </p><p> + Lombok does not (currently) have any runtime dependencies which means lombok does not (currently) ship with any useful + extension methods so you'll have to make your own. However, here's one that might spark your imagination: + <pre>public class ObjectExtensions { + public static <T> or(T object, T ifNull) { + return object != null ? object : ifNull; + } +}</pre> + With the above class, if you add <code>@ExtensionMethod(ObjectExtensions.class)</code> to your class definition, you can write: + <pre>String x = null; +System.out.println(x.or("Hello, World!"));</pre> + The above code will not fail with a <code>NullPointerException</code>; it will actually output <code>Hello, World!</code> + </p> + </div> + <div class="snippets"> + <div class="pre"> + <h3>With Lombok</h3> + <div class="snippet">@HTML_PRE@</div> + </div> + <div class="sep"></div> + <div class="post"> + <h3>Vanilla Java</h3> + <div class="snippet">@HTML_POST@</div> + </div> + </div> + <div style="clear: left;"></div> + <div class="overview"> + <h3>Small print</h3><div class="smallprint"> + <p> + Calls are rewritten to a call to the extension method; the static method itself is not inlined. Therefore, the + extension method must be present both at compile and at runtime. + </p><p> + Generics is fully applied to figure out extension methods. i.e. if the first parameter of your extension method is + <code>List<? extends String></code>, then any expression that is compatible with that will have your extension method, + but other kinds of lists won't. So, a <code>List<Object></code> won't get it, but a <code>List<String></code> will. + </p> + </div> + </div> + <div class="footer"> + <a href="index.html">Back to experimental features</a> | <a href="Accessors.html">Previous feature (@Accessors)</a> | <span class="disabled">Next feature</a><br /> + <a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright © 2009-2012 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span> + </div> + <div style="clear: both;"></div> + </div> +</div> +<script type="text/javascript"> + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); +</script> +<script type="text/javascript"> + try { + var pageTracker = _gat._getTracker("UA-9884254-1"); + pageTracker._trackPageview(); + } catch(err) {} +</script> +</body></html> diff --git a/website/features/experimental/index.html b/website/features/experimental/index.html index e4e90c41..9b25d710 100644 --- a/website/features/experimental/index.html +++ b/website/features/experimental/index.html @@ -24,6 +24,8 @@ <dl> <dt><a href="Accessors.html"><code>@Accessors</code></a></dt> <dd>A more fluent API for getters and setters.</dd> + <dt><a href="ExtensionMethod.html"><Code>@ExtensionMethod</code></a></dt> + <dd>Annoying API? Fix it yourself: Add new methods to existing types!</dd> </dl> </div> <div class="footer"> |