Tuesday, 16 December 2008

Java Garbage Collection for String literals

Tonight I had a ponder about Javas garbage collection mechanism and what would make an object held by a WeakReference be garbage collected. The answer was quite simple, create a instance of a variable, create a WeakReference for it, null the instance and call System.gc(). I'm guessing that the instance would be garbage collected on the next natural sweep but because I was using a unit test I needed it to be done straight away.

However, garbage collection on string literals is far more interesting. See the unit tests.

import static org.junit.Assert.*;

import java.lang.ref.WeakReference;

import org.junit.Test;

public class ReferenceTest
{
@Test
public void testWeakReference()
{
Object reference = new Object();

WeakReference<Object> weakRef =
new WeakReference<Object>(reference);

assertNotNull(reference);

reference = null;

// reference will not be null
// without garbage collection here
System.gc();

assertNull(weakRef.get());
}

@Test
public void testWeakStringReference()
{
String reference = new String();

WeakReference<String> weakRef =
new WeakReference<String>(reference);

assertNotNull(reference);

reference = null;

// reference will not be null
// without garbage collection here
System.gc();

assertNull(weakRef.get());
}

@Test
public void testWeakStringLiteralReference()
{
String reference = "my reference";

WeakReference<String> weakRef =
new WeakReference<String>(reference);

assertNotNull(reference);

reference = null;

// does not matter if garbage collection
// is here or not but lets do it anyway
System.gc();

// !!!
assertNotNull(weakRef.get());
}
}





All of these tests pass. Notice the last test, even after the string instance has been nulled the WeakReference still has a not null value. After a bit of googling I found that string literals are referenced from Javas 'String Literal Pool' which is a cache for string literals so is not eligible for garbage collection!

Saturday, 11 October 2008

Turn off no serialVersionUID warnings in eclipse

A bit of madness that I've always asscoiated with eclipse is that it shows a warning if a Java class does not have a serialisable UID, for example, something like the following...


public class MyTreeModel extends DefaultTreeModel
{
    private static final long serialVersionUID = 7522249943744455803L;
}


If I see this then I know its been written using eclipse, to turn it off go to the project's properties. In the tree follow Java Compiler->Errors/Warnings. To configure this for all projects click on Configure Workspace Settings... In the list of categories choose Potential Programming Problems and the setting for serial UIDs is top of the list, here you can it to ignore.

Tuesday, 23 September 2008

Decorating a Swing Action

I've got into the decorator pattern since reading Swing Hacks as a way to add some functionality to a class or even an interface (see the JTable sorting hack!) without changing it. I recently needed a way of adding functionality to Swing Actions that was specific to where they were used, this time disposing a JFrame but only when its used in that JFrame. The solution is to create a wrapper for the action that delegates all method calls to the wrapped action but has method hooks that that are called before and after the wrapped action's actionPerformed method is called which are overridable.


public class AbstractWrapperAction extends AbstractAction {
Action wrappedAction;

public AbstractWrapperAction(Action wrappedAction) {
this.wrappedAction = wrappedAction;
}

public void actionPerformed(ActionEvent e) {
preWrappedAction(e);

if(wrappedAction != null)
{
wrappedAction.actionPerformed(e);
}
postWrappedAction(e);
}

public void preWrappedAction(ActionEvent e) { }

public void postWrappedAction(ActionEvent e) { }

@Override
public void setEnabled(boolean b) {
wrappedAction.setEnabled(b);
}

@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
wrappedAction.removePropertyChangeListener(listener);
}

@Override
public void putValue(String key, Object value) {
wrappedAction.putValue(key, value);
}

@Override
public boolean isEnabled() {
return wrappedAction.isEnabled();
}

@Override
public Object getValue(String key) {
return wrappedAction.getValue(key);
}

@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
wrappedAction.addPropertyChangeListener(listener);
}
}


And an example usage is below...


Action wrapperAction = new AbstractWrapperAction(action) {
@Override public void postWrappedAction(ActionEvent e) {
((Window)getValue(FRAME_KEY)).dispose();
}
};
wrapperAction.putValue(FRAME_KEY, myJFrame);


Here myJFrame is an instantiated JFrame and action is your original action implementation, myJFrame will now be disposed once the action is triggered.

Saturday, 21 June 2008

JPopupMenu and ActionEvent's getSource( ) Method

When handling an event from a Java Swing component you would most likely implement the ActionListener interface and be able to get the source of the event from the ActionEvent's getSource() property. Not so if the event was triggered by a JPopupMenu. The type of the source of an ActionEvent is actually JPopupMenu$1 which seems to be a private inner class of JPopupMenu. The hack round this is pretty simple but not obvious because JPopupmenu$1 isn't documented anywhere.

JPopupMenu$1 extends Component and its parent is the JPopupMenu that you wanted in the first place so all you have to do is cast it and call getParent().

Thursday, 19 June 2008

COM Scripting in Groovy

Today I needed to test a COM component to make sure it worked as I expected, and to learn a bit about it at the same time. This isn't as easy as it used to be! COM components have fallen seriously out of favour (and for good reason), the effect of this seems to be that the components live on but the consuming languages aren't easily available. I could have created a wrapper using .net but this always seems an ugly and overweight solution.

Groovy has a far more elegant way of handling COM, involving no compilation (apart from what is done in memory) and everything you need comes with the Groovy SDK. In hardly took any time to get this small example of how to send an SMS using the Esendex COM component.


import org.codehaus.groovy.scriptom.*

Scriptom.inApartment {
   def service = new ActiveXObject("Esendex.SendService2");
   service.Initialise("MyUserName", "MyPassword", "MyAccount");
   service.SendMessage("441234567890", "Hello", 1);
}


The above code is a mashup of the examples on the Scriptom Page and the Esendex VB SDK Page. Its mostly self explanatory, the inApartment method takes a closure containing your COM scripting. Note that the third argument in the SendMessage call, 1, tells the COM object that the SMS is a text message. Remember to install the COM dll using regsvr32 and replace the username, password and account info with your own.

Advantages over VB6 and VBA? Its really easy to thread, and you don't have to find that decade old installation disc :)

Wednesday, 11 June 2008

A quick PHP testing tip for my first post. PHP's configuration file typically called php.ini is almost as important as the source code of a project in my experience. PHP code can give different results depending on how the environment is set up which can be frustrating when you begin deploying to a different environment and things start going wrong. In my case, after developing the first pass of the Esendex PHP ReST SDK I gave it to a colleague to review and it threw warnings. The offender was the following...

if(!defined(ESENDEX_HOME))
{
define('ESENDEX_HOME', '');
}

You might have seen the problem straight away, the defined function requires a string and not a constant name. The error_reporting property in my php.ini file was set quite low (not including E_NOTICE) so it didn't throw a warning. The quick way of catching all these syntax errors during development is to set the error_reporting property to E_ALL which will throw warnings over any mistake, this can be done with the error_reporting function.

error_reporting(E_ALL);

Now you get to spend the next half hour going through your project fixing all the bugs you never knew you had!