I just found a Java “got’cha” (there certainly are plenty aren’t there?).
When a Java object is constructed the super class constructor is called first. So far this makes sense. But this also applies to initializations that are written at the point of declaration like:
Object obj = null;
This is different then leaving out the = null
in that obj
is nulled after the superclass constructor runs. This is usually not a problem, but I have a situation where some of the initialization occurs in a method called from the superclass constructor (this is a dubiously good design I know). The result is that if the initialization method called from the superclass sets obj
that change will be overwritten with null
in the subclass constructor.
It took me several hour to find this problem. I’m going to be much more careful with calls to virtual functions in the constructor. It is considered bad form for a reason. Also this is one of the few times I have started to understand why the functional programming fan boys bash on object oriented programming. The OO methodology is flawed in a number of ways. That being said I think there is a place for it. It models the real world of things that can interact in a very nice way. I think that the actor model may turn out to be better, but that will take time.
Posted in
Java,
Programming Theory
I have been using Metawidget (which is a really cool library by the way) on a project lately. I wanted to avoid the need for a save button by having changes automatically propagated to the beans when changes are made to the widgets. However I am using BeanUtils (from apache) which does not support binding internally.
I did try BeanBinding but it was really slow (I don’t know why and I didn’t have time to debug it). So I created an extension to the BeanUtilsBinding class (from Metawidget) that adds auto-save support. It’s a really ugly hackish implementation but it works reliably (though I think there may be corner cases where the save does not trigger when it should). It is also quite fast. It doesn’t run the save until all the messages currently in the swing queue are processed (using SwingUtilities.invokeLater
) and then it only runs it once so even if a lot of changes happen at the same time only one save will be done.
The implementation is below. Feel free to use it. It is copyright Arthur Peters under the GNU GPL v3.
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.metawidget.swing.SwingMetawidget;
import org.metawidget.swing.propertybinding.beanutils.BeanUtilsBinding;
public class BeanUtilsAutoUpdateBinding extends BeanUtilsBinding {
@SuppressWarnings("unused")
private static final Logger log = Logger
.getLogger("BeanUtilsAutoUpdateBinding");
protected static final class ListenToRecord {
private final Component component;
private final String propertyName;
public ListenToRecord(Component component, String propertyName) {
this.component = component;
this.propertyName = propertyName;
}
public Component getComponent() {
return component;
}
public String getPropertyName() {
return propertyName;
}
}
private List listeningTo = new ArrayList();
private ChangeListener changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
doSave();
}
};
private ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doSave();
}
};
/*private DocumentListener documentListener = new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
doSave();
}
@Override
public void insertUpdate(DocumentEvent e) {
doSave();
}
@Override
public void removeUpdate(DocumentEvent e) {
doSave();
}
};
*/
private KeyListener keyListener = new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
doSave();
}
@Override
public void keyReleased(KeyEvent e) {
doSave();
}
@Override
public void keyTyped(KeyEvent e) {
doSave();
}
};
private MouseListener mouseListener = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
doSave();
}
@Override
public void mouseEntered(MouseEvent e) {
// Ignore
}
@Override
public void mouseExited(MouseEvent e) {
// Ignore
}
@Override
public void mousePressed(MouseEvent e) {
// Ignore
}
@Override
public void mouseReleased(MouseEvent e) {
doSave();
}
};
private FocusListener focusListener = new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
// Ignore
}
@Override
public void focusLost(FocusEvent e) {
doSave();
}
};
private boolean saveAlreadyInEventQueue;
public BeanUtilsAutoUpdateBinding(SwingMetawidget metawidget) {
super(metawidget);
}
@Override
public void bindProperty(Component component,
Map attributes, String path) {
super.bindProperty(component, attributes, path);
String valueProperty = getMetawidget().getValueProperty(component);
// component.addPropertyChangeListener(valueProperty, this);
attemptToCall(component, "addChangeListener", ChangeListener.class,
changeListener);
attemptToCall(component, "addActionListener", ActionListener.class,
actionListener);
// attemptToCall(component, "addDocumentListener",
// DocumentListener.class, documentListener);
component.addKeyListener(keyListener);
component.addMouseListener(mouseListener);
component.addFocusListener(focusListener);
listeningTo.add(new ListenToRecord(component, valueProperty));
}
private void attemptToCall(Component component, String methodName,
Class eventListenerCls,
EventListener eventListener) {
try {
Class cls = component.getClass();
Method method = null;
while (method == null && cls != Object.class) {
try {
method = cls.getMethod(methodName, eventListenerCls);
} catch (NoSuchMethodException e) {
// Ignore
}
cls = cls.getSuperclass();
}
method.invoke(component, eventListener);
} catch (Exception e) {
// Ignore it and return. This function is an attempt.
log.log(Level.FINE, "Failed to call " + methodName + " on "
+ component, e);
}
}
@Override
public void unbindProperties() {
super.unbindProperties();
for (ListenToRecord listenToRecord : listeningTo) {
Component component = listenToRecord.getComponent();
// component.removePropertyChangeListener(listenToRecord.getPropertyName(),
// this);
component.removeKeyListener(keyListener);
component.removeMouseListener(mouseListener);
attemptToCall(component, "removeChangeListener",
ChangeListener.class, changeListener);
attemptToCall(component, "removeActionListener",
ActionListener.class, actionListener);
// attemptToCall(component, "removeDocumentListener",
// DocumentListener.class, documentListener);
}
listeningTo.clear();
}
protected void doSave() {
synchronized (this) {
if (!saveAlreadyInEventQueue) {
saveAlreadyInEventQueue = true;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getMetawidget().save();
synchronized (BeanUtilsAutoUpdateBinding.this) {
saveAlreadyInEventQueue = false;
}
}
});
}
}
}
}
Posted in
Java,
Programming
When Google App Engine first came out I was really surprised it didn’t support Java, because Google was (and is) really pushing GWT, so to have them release a web deployment platform that did not support their own favorite framework was odd. However they have now released a preview version of Google App Engine running Java. It doesn’t do everything I might want, for instance Lift doesn’t run on it out of the box and it doesn’t allow you to spawn your own threads (these problems are directly related). There is some work going on to make Lift work on it though (see the email thread).
Overall though I’m really excited. I have been looking for a platform that will allow me to run Java based web apps for a reasonable price and I think this is the first one that provides something that I may actually use. For a low traffic site it is free and it looks to me that the prices are pretty good even as the traffic increases.
Posted in
Java,
Scala
I ran into a problem with installing Subversive (An eclipse plugin that interfaces to Subversion). The issue is that the plugin comes in 2 pieces that are both required: the Subversive plug-in and the Subversive SVN Connectors plug-in. This was not obvious to me and I ran into this problem not once but twice.
The solution is to add these 2 update sites (current as of Apr 2nd, 2009):
- http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/
- http://download.eclipse.org/technology/subversive/0.7/update-site/
And install the following features from them:
- Subversive SVN Team Provider (from the http://download.eclipse.org/technology/subversive/0.7/update-site/ site)
- Subversive SVN Connectors (from the http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/ site)
- SVNKit 1.2.2 Implementation (from the http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/ site)
The error message in the eclipse logs was as follows when I failed to add the site for and install the “Subversive SVN Team Provider”. I hope this will help people find this and not have the same problems I did.
!ENTRY org.eclipse.equinox.p2.ui 4 10005 2009-04-06 15:30:28.470
!MESSAGE Cannot complete the request. See the details.
!SUBENTRY 1 org.eclipse.equinox.p2.ui 4 10005 2009-04-06 15:30:28.470
!MESSAGE Cannot complete the request. See the details.
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.470
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.feature.group 2.1.0.I20090213-1500] requiredCapability: org.eclipse.equinox.p2.iu/org.eclipse.team.svn.feature.group/[0.7.2.I20080801
-1500,1.0.0)
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.470
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.svnkit15.feature.group 2.1.0.I20090213-1500] requiredCapability: org.eclipse.equinox.p2.iu/org.eclipse.team.svn.feature.group/[0.7.2.I20080801-1500,1.0.0)
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.470
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.svnkit15 2.1.0.I20090213-1500] requiredCapability: osgi.bundle/org.eclipse.team.svn.core/0.0.0
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.470
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.svnkit15 2.1.0.I20090213-1500] requiredCapability: osgi.bundle/org.eclipse.team.svn.core/0.0.0
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.471
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.feature.group 2.1.0.I20090213-1500] requiredCapability: org.eclipse.equinox.p2.iu/org.eclipse.team.svn.feature.group/[0.7.2.I20080801-1500,1.0.0)
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.471
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.svnkit15.feature.group 2.1.0.I20090213-1500] requiredCapability: org.eclipse.equinox.p2.iu/org.eclipse.team.svn.feature.group/[0.7.2.I20080801-1500,1.0.0)
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.471
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.svnkit15.feature.group 2.1.0.I20090213-1500] requiredCapability: org.eclipse.equinox.p2.iu/org.polarion.eclipse.team.svn.connector.feature.group/0.0.0
!SUBENTRY 1 org.eclipse.equinox.p2.director 4 0 2009-04-06 15:30:28.471
!MESSAGE Unsatisfied dependency: [org.polarion.eclipse.team.svn.connector.svnkit15.feature.group 2.1.0.I20090213-1500] requiredCapability: org.eclipse.equinox.p2.iu/org.polarion.eclipse.team.svn.connector.svnkit15/[2.1.0.I20090213-1500,2.1.0.I20090213-1500]
Posted in
Java,
Tooling
[EDIT: It has been pointed out that the correct term for what I am talking about is Scalar Replacement. Also it seems that Java 7 already has some code to support it in the JIT compiler. Thanks.]
One of the interesting features of Scala is the ability to use implicit conversions to “add” methods to existing classes. A call to “x.func” will try to convert x to a type with a method func if it doesn’t naturally have one. The problem is that each time this happens it ends up allocating a temporary wrapper object. This is similar to Java idioms like:
long time = new Date().getTime();
In both cases an object is allocated and then is immediately ready to be garbage collected. Whenever I think about this I feel that the JVM could optimize it away. Maybe something like this.
The JVM discovers (during escape analysis, which I think it already does) that the object is short lived and local. It then inlines the small number of method calls (often just one, especially in the case of scala implicit conversions). When it sees that every method call on the object is inlined it inlines the constructor and converts any fields of the class into local variable and removes the allocation entirely.
This wouldn’t be easy. But it doesn’t seem like it would be too incredibly hard. Though I’m not a JVM programmer so I don’t really know.
Maybe I should give it a shot. I’ve never hacked on Hotspot and I’ve always kinda wanted to.
Any thoughts on this?
Posted in
Java,
JVM,
Scala
One of the common complaints that people have about Java is that it lacks the const keyword. Yes, Java has final, but final cannot create a reference to a immutable object only a immutable reference to a mutable object.
The issue is that there is no way to encode the promise that an object will not be mutated in the Java language. The work around for this is to create a wrapper object that throws an exceptions if a mutator method is called. This is how the collection API handles the problem. However this technique provides no compile time checks. There is no way to know at compile time if a given Collection is mutable or immutable.
I have thought about this a bit lately and I have realized that const as it is implemented in C++ is fundamentally a way of defining a sub-interface of the interface to a class. I mean this in the sense that the interface of “const Thing” is a subset of the interface of “Thing”. So in essence “const Thing” can be thought of as a abstract base class of “Thing” (with the exception that casting “const Thing” to “Thing” should be hard or impossible). What I’m getting at is that you could generalize this idea into the idea of a interface subset.
In Java this could be implemented by hand as follows:
public interface ConstThing {
public String getValue();
}
public class Thing implements ConstThing {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public class ConstThingProxy implements ConstThing {
final private Thing subject;
public ConstThingProxy(Thing subject) {
this.subject = subject;
}
public String getValue() {
return subject.getValue();
}
}
// Usage:
public class Client {
public void useMutable(Thing t) {
t.setValue("New");
}
public void useConst(ConstThing t) {
t.getValue();
t.setValue("New"); // <-- Compiler Error
}
public void useConstCast(ConstThing t) {
t.getValue();
((Thing) t).setValue("New");
/*
* No compiler error, but there would be a runtime error if the code
* providing the ConstThing wrapped the reference in a
* ConstThingProxy.
*/
}
}
Obviously this has a number of missing features and is hard to do because the interface must be declared by hand. So the main missing features from this approach are (in rough order of importance):
- There should be an easy way to create this structure of classes. In other words, there should be syntactic sugar for it or something like that.
- There should be a way to make the this reference in a function be an instance of all of the interface subsets that the method it part of. This would allow the compiler to provide warnings or errors if the method references elements of the class that are not part of the interface subset. This is actually a very complex problem, especially when combined with inheritance. I don’t have a solution for it that I am comfortable with.
I may come back to this subject later. For instance I think it would be interesting to see if it can be implemented better in Scala with it’s more expressive type system.
Posted in
Java,
Programming Theory