Jose Juan MontielJose Juan Montiel

Retrolambda and Hippo Cms

This project can only be compiled with the JDK 8 as it makes heavy use of its features: lambdas, default methods and more.

Thanks to Retrolambda, many projects that make use of the new features of JDK 8 can be migrated to JDK7 (and earlier) and therefore also to Android, where primary use is made this tool.

And with this maven plugin you can integrate it into your buildsystem. Here is an example of how to use it. And besides, there is another for Gradle.

Limitations

But there are some well known limitations, which makes the migration of the default method of JDK 8 are not so easy, "must to be backported together, with one execution of Retrolambda".

So by default is disabled in the migration.

When Retrolmambda migrates Default Methods: Default methods are backported by copying the default methods to a companion class (interface name + "$") as static methods, replacing the default methods in the interface with abstract methods, and by adding the Necessary method Implementations to all classes which implement that interface.

Retrolambda (and HippoCms)

Take, for example, the following project.

Suppose that initially have this interface module with the default method.

public interface IconProvider extends IClusterable {
	default Component getIcon(final String id, IconSize size) {
		return null;
	}
}

Retrolambda what makes this class is transformed into this one.

public abstract interface IconProvider2 extends IClusterable {
  public abstract Component getIcon(String paramString, IconSize paramIconSize);
}

And implements that method (through the "companion class") in classes that implement the interface, classes in the same module.

Therefore, if not process all child classes that interface module in the past, and will not, so…​

public class SearchingSectionPlugin extends RenderPlugin implements IBrowserSection

this in another module, trying to be compiled gives this error

[ERROR] /hippo-cms/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/SearchingSectionPlugin.java:[63,7]
	error: SearchingSectionPlugin is not abstract and does not override abstract method getIcon(String,IconSize) in IconProvider

First conclusions

At first, unread well the error message, and without understanding the class hierarchy of the project, I thought it might help this PR

If you want to understand more in detail, here some notes on the Lifecycle of maven. And here on classloading.

Then read more in detail, I thought the problem was that the transformation the interface to abstract …​ well, i admit this tweet had distracted me from the real problem, because the interfaces are abstract (by default).

And the own Esko Luontola explains why. "8 pre-Java JVMs support only abstract methods in interfaces (the <clinit> method being an exception). Retrolambda code inserts the default method implementing to all classes, JVM 8 thus emulating what does."

Here a more detailed explanation of how to operate the Default Methods in JDK 8. And here oracle’s explanation on "abstract".

Explanation of the real problem

But the problem, in this case, was simply the limitation of the library in multi module projects here and here as also discussed in detail.

A way out by making small manual changes in the code, it would be implementing the method getIcon(String, IconSize) with the default behavior in class the second module.

diff --git a/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/BrowsingSectionPlugin.java b/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/BrowsingSectionPlugin.java
index 99bdb0e..9b34ce1 100644
--- a/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/BrowsingSectionPlugin.java
+++ b/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/BrowsingSectionPlugin.java
@@ -18,6 +18,7 @@
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;

+import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.request.resource.ResourceReference;
 import org.hippoecm.frontend.l10n.ResourceBundleModel;
@@ -144,4 +145,10 @@
         return null;
     }

+    @Override
+    public Component getIcon(String id, IconSize size) {
+    	return null;
+    }
+
+
 }
diff --git a/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/SearchingSectionPlugin.java b/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/SearchingSectionPlugin.java
index 450712b..9d09210 100644
--- a/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/SearchingSectionPlugin.java
+++ b/perspectives/src/main/java/org/hippoecm/frontend/plugins/cms/browse/section/SearchingSectionPlugin.java
@@ -56,6 +56,7 @@
 import org.hippoecm.frontend.service.IconSize;
 import org.hippoecm.frontend.service.render.RenderPlugin;
 import org.hippoecm.frontend.skin.Icon;
+import org.hippoecm.frontend.skin.IconProvider;
 import org.hippoecm.repository.api.HippoNodeType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -337,6 +338,11 @@
     public ResourceReference getIcon(IconSize type) {
         return null;
     }
+
+    @Override
+    public Component getIcon(String id, IconSize size) {
+    	return null;
+    }

     private boolean hasSearchResult() {
         return collection.getType() == DocumentCollectionType.SEARCHRESULT;

Next steps?

Teras and Orfjackal, why the PR 101 does not modify these classes to make that change? Maybe it does because there is already a method with that name, although not with the same number of parameters?

And what happend with the retrolambda compilation of HippoCms?

Even some mistake …​ we have to solve static method …​

[ERROR] hippo-cms/workflow/frontend/src/main/java/org/hippoecm/frontend/plugins/reviewedactions/list/ReviewedActionsListColumnProviderPlugin.java:[72,38] error: cannot find symbol
[ERROR] symbol:   method of(Calendar)
[ERROR] location: interface DateTimePrinter
[ERROR] hippo-cms/workflow/frontend/src/main/java/org/hippoecm/frontend/plugins/reviewedactions/list/ReviewedActionsListColumnProviderPlugin.java:[79,38] error: cannot find symbol
[ERROR] symbol:   method of(Calendar)
[ERROR] location: interface DateTimePrinter

Static methods on interfaces are backported by moving the static methods to a companion class (interface name + "$"), and by changing all methods calls to call the new method location.[1]

In this case, the temporary solution is to change the import in the classes of the second module, the companion class.

diff --git a/workflow/frontend/src/main/java/org/hippoecm/frontend/plugins/reviewedactions/RequestsView.java b/workflow/frontend/src/main/java/org/hippoecm/frontend/plugins/reviewedactions/RequestsView.java
index 5a97066..ab938b7 100644
--- a/workflow/frontend/src/main/java/org/hippoecm/frontend/plugins/reviewedactions/RequestsView.java
+++ b/workflow/frontend/src/main/java/org/hippoecm/frontend/plugins/reviewedactions/RequestsView.java
@@ -41,7 +41,7 @@
 import org.hippoecm.frontend.plugin.IPluginContext;
 import org.hippoecm.frontend.plugins.reviewedactions.model.Request;
 import org.hippoecm.frontend.plugins.reviewedactions.model.RequestModel;
-import org.hippoecm.frontend.plugins.standards.datetime.DateTimePrinter;
+import org.hippoecm.frontend.plugins.standards.datetime.DateTimePrinter$;
 import org.hippoecm.frontend.plugins.standards.icon.HippoIcon;
 import org.hippoecm.frontend.session.UserSession;
 import org.hippoecm.frontend.skin.Icon;
@@ -110,7 +110,7 @@
                 String state = request.getState();

                 final String parameter = schedule != null ?
-                        DateTimePrinter.of(schedule).appendDST().print(FormatStyle.FULL) : "??";
+                        DateTimePrinter$.of(schedule).appendDST().print(FormatStyle.FULL) : "??";
                 return new StringResourceModel("state-" + state, this, null, "unknown", parameter);
             }

Final notes

If you’ve used in your project with JDK 8 are streaming APIs, you can use this.

Here is a brief history.