Friday, April 16, 2010

Spring PropertyEditor for JSON map and array properties

I'm a big fan of Spring but found that it does not support map and list expressions in a property file to be substituted when using a PropertyPlaceholder. So I rolled my own PropertyEditor and can now express a map using JSON in my properties file e.g.:

myMapProperty ={"en-AU": "SKY", "ms": "SKY"}

Here's the property editor (depends on json-lib):

package <packagename>;

import java.beans.PropertyEditorSupport; 

import net.sf.json.JSON;
import net.sf.json.JSONSerializer;

/**
* Converts JSON expressions to Java arrays or maps and vice versa.
*
* @author huntc
*
*/
public class JSONPropertyEditor extends PropertyEditorSupport {

@Override
public String getAsText() {
Object object = getValue();
JSON jsonObject = JSONSerializer.toJSON(object);
return jsonObject.toString();
}

@Override
public void setAsText(String text) {
JSON json = JSONSerializer.toJSON(text);
setValue(json);
}
}

and here's what you must declare in your spring configuration xml:

<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Map">
<bean class="<packagename>.JSONPropertyEditor" />
</entry>
</map>
</property>
</bean>

The above indicates that for any required substitution of a map, use my property editor e.g.:

<bean id="someBeanWithAMapProperty"
class="someClass">
<property name="someMapProperty"
value="${myMapProperty}" />
</bean>

 

Tuesday, April 13, 2010

iPhone and multitasking

So here we are. Apple appears to be finally opening up the threading APIs to developers on the iPhone.

I've had numerous conversations with colleagues since the iPhone came out and they've been all sorts of reactions as to why there's no multithreading. Actually, now that I've just typed multithreading let's get this straight. Multitasking relates to the human experience of doing multiple things at the same time; it is a use-case; it is something that I've been told (by my wife) that men can't do and women can (!).

Multithreading is the ability for an OS to cooperatively or pre-emptively (generally the latter) slice processor time between different paths of execution within and outside of a number of processes (generally applications).

The iPhone has supported multitasking and multithreading forever. The difference now is that Apple appears to have opened up the multithreading API to non-Apple developers. I've not seen the details on this, perhaps they've constrained the thread APIs in some interesting way with the goal of limiting battery usage, but it is a very good (and necessary) thing that there will now be multithreading.

One application that I'm really looking forward to using is Skype. Finally, we'll be able to receive Skype calls with the same experience of receiving regular mobile calls; so long as you're on a WiFi network of course. I think that this will be amazing as I'm never near my computer when someone wants to contact me via Skype. However, I always have my iPhone at hand of course.

I can't wait for SIP supporting applications to come along for the iPhone either. The prospect of receiving my home phone calls when away from home via VOIP is fantastic.

Oh and one thing I'd like to joyfully throw back at the multithreading doubters: get over it. Yes, multithreaded programming is harder but its just the way the world is. Multiple things happen at the same time. Embrace it.

Well done Apple. I look forward to iPhone 4.0.

Monday, April 12, 2010

The pitfall of setting a list of parameters on a JQL query

I recently had a need to provide a collection as a parameter to a JQL IN expression. This is what I did:

List results = getJpaTemplate()
.find(
"from AbstractEvent e "
+ "where "
+ "(e.subscription, e.eventTime) in "
+ "(select e.subscription, max(e.eventTime) "
+ "from e "
+ "where "
+ "e.class in "
+ "(SentSMSFlightSubscribed,"
+ " ReceivedSMSFlightUnsubscribe) and "
+ "e.subscription.flightNo in (?) and "
+ "e.subscription.scheduled = ? "
+ "group by e.subscription)",
renderedFlight.getFlights(),
renderedFlight.getScheduled());

The problem with the query is that you get a class cast exception when an attempting to substitute the collection (renderedFlight.getFlights) .

To fix this you simply need to be explicit about the parameters:

    + "e.subscription.flightNo in (?1) and "
+ "e.subscription.scheduled = ?2 "

Problem solved.

Updated: Sunday 11 July 2010: Even using position parameters doesn't always work. While it works in the above example it didn't work for me when using a parameter of a non-primitive type; at least I think that was the issue. So in a nutshell, if the above doesn't work for you then just use findByNamedParams instead.

You may also note this beauty of a line:

e.class in (
SentSMSFlightSubscribed,
ReceivedSMSFlightUnsubscribe)

That is how you perform an "instanceof" style of operation in JQL. Nice.