{"id":1281,"date":"2011-03-23T15:24:52","date_gmt":"2011-03-23T15:24:52","guid":{"rendered":"http:\/\/salientsoft.co.uk\/?p=1281"},"modified":"2011-03-23T15:46:11","modified_gmt":"2011-03-23T15:46:11","slug":"java-genericsclass-literals-as-run-time-type-tokens","status":"publish","type":"post","link":"https:\/\/salientsoft.co.uk\/?p=1281","title":{"rendered":"Java Generics&ndash;Class literals as run time type tokens"},"content":{"rendered":"<p>This post refers to the section on page 16 of the <a href=\"http:\/\/java.sun.com\/j2se\/1.5\/pdf\/generics-tutorial.pdf\"><strong>Generics tutorial document<\/strong><\/a> by Gilad Bracha.<\/p>\n<p>The example here uses the <a href=\"http:\/\/cojen.sourceforge.net\/\"><strong>Cojen<\/strong><\/a> dynamic bytecode generation library in order to create custom sort comparators. The advantage of Cojen is that you end up with a fully compiled comparator and therefore do not incur the performance hit of reflective code. Furthermore, comparators generated by Cojen can be cached in a map so that they are only generated once. This particular example borrows some code originally used for Icefaces table sorting, which I adapted for use with Primefaces. Whilst Primefaces does have its own table sorting, I had some issues with it. I wanted visibility of the current sort column and direction, and I wanted control over the sorting \u2013 I wanted to reapply the sort to a table when rows were added to it from another table, so that it was always maintained in order. Furthermore, I wanted to maintain the current sort column and direction that had been selected by the user via the column headers when applying the sort when new rows were added. As I had trodden this route before for Icefaces, it was straightforward to move the code over and incorporate it into a standard table controller class which I was already developing.<\/p>\n<p>One issue which I had not previously bottomed out in the Icefaces version was making the code fully generic and fully eliminating all the generic warnings when using a class literal as a run time type token. With Cojen, you call a static <em>forClass<\/em> method on its BeanComparator to construct a comparator, passing in the class and the comparator ordering details:-<\/p>\n<p style=\"padding-left: 30px;\"><em>if (beanComparator == null) {<br \/>\n\u00a0\u00a0\u00a0 beanComparator = BeanComparator.forClass(rowClass).orderBy(key);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<br \/>\n\u00a0\u00a0\u00a0 comparatorMap.put(key, beanComparator);<br \/>\n}\u00a0\u00a0\u00a0 <\/em><\/p>\n<p>In my first Icefaces attempt, I pulled the first row out of the current row list for the table, and passed that to Cojen to create the class. The problem with this was that I could not do it generically this way. My second attempt, with the Primefaces version, passed the class in to an init method generically. As this tied up all the generics loose ends correctly, everything was happy and the class was recognised as having the correct parameterised type. The cost of this was the need to pass it explicitly as an argument to an init method (or a setter), but this was simple and made the parameterised type clear and explicit. This is\u00a0the correct\u00a0approach and one that I will use from now on.<\/p>\n<p>The following code fragments illustrate the mechanism:-<\/p>\n<p><strong><span style=\"text-decoration: underline;\">Call Site<\/span><\/strong><\/p>\n<p><em><strong>\u2026<br \/>\n\u00a0\u00a0\u00a0 private @Inject TableCtrl&lt;Person, RowMetadata&gt; personTable;<br \/>\n\u2026<\/strong><br \/>\n<strong>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 personTable.init(Person.class, RowMetadata.class, this);<\/strong><\/em><\/p>\n<p>\u00a0<\/p>\n<p><strong><span style=\"text-decoration: underline;\">TableCtrlImpl.java<\/span><\/strong><\/p>\n<p>@Dependent<br \/>\n<strong><em>public class TableCtrlImpl&lt;C, D extends RowMetadata&gt; implements Serializable, TableCtrl&lt;C, D&gt;, Iterable&lt;C&gt; {<br \/>\n<\/em><\/strong>\u2026<br \/>\n\u00a0<strong><em>\u00a0\u00a0 private Class&lt;C&gt; rowClass;<br \/>\n\u2026<br \/>\n\u00a0\u00a0\u00a0 private Map&lt;String, BeanComparator&lt;C&gt;&gt; comparatorMap = new HashMap&lt;String, BeanComparator&lt;C&gt;&gt;();<br \/>\n<\/em><\/strong>\u2026<\/p>\n<p><em><strong>@Override public void init(Class&lt;C&gt; rowClass, Class&lt;D&gt; rowMetadataClass, TableCtrlEvent&lt;C, D&gt; tableCtrlEvent) {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<br \/>\n<\/strong><\/em>\u00a0\u00a0\u00a0 rowMeta = new RowMetaMap&lt;C, D&gt;();<br \/>\n\u00a0 <em><strong>\u00a0 this.rowClass = rowClass;<br \/>\n<\/strong><\/em>\u00a0\u00a0\u00a0 this.rowMetadataClass = rowMetadataClass;<br \/>\n\u00a0\u00a0\u00a0 this.tableCtrlEvent = tableCtrlEvent;<br \/>\n}<br \/>\n\u2026<br \/>\n\u00a0\u00a0\u00a0 @Override public void sort() {<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (sortColumn != null &amp;&amp; !rows.isEmpty()) {<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String key = (sortAscending ? &#8220;&#8221; : &#8220;-&#8220;) + sortColumn;<br \/>\n<em><strong>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 BeanComparator&lt;C&gt; beanComparator = comparatorMap.get(key);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (beanComparator == null) {<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 beanComparator = BeanComparator.forClass(rowClass).orderBy(key);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 comparatorMap.put(key, beanComparator);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/strong><\/em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Collections.sort(rows, beanComparator);<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<br \/>\n\u00a0\u00a0\u00a0 }<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post refers to the section on page 16 of the Generics tutorial document by Gilad Bracha. The example here uses the Cojen dynamic bytecode generation library in order to create custom sort comparators. The advantage of Cojen is that you end up with a fully compiled comparator and therefore do not incur the performance [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[7],"tags":[142,40,181,16,15],"_links":{"self":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/1281"}],"collection":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1281"}],"version-history":[{"count":10,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/1281\/revisions"}],"predecessor-version":[{"id":1289,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/1281\/revisions\/1289"}],"wp:attachment":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1281"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1281"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1281"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}