Friday, May 16, 2008

Updating Composite-id Object

Before continuing, I use appfuse-spring-hibernate, FYI. Ok, I already had Financial object with composite keys that I generate directly from my Pojo, now I get error if I update a record of it.

It's just said that it failed to convert from String to FinancialPk. And when I debug it, in FinancialFormController, it never enter the onSubmit method, there's same error when in processFormSubmission method.

This error is happened for two days, I already browse the net, asked some people, but still don't get the answer, so I encourage myself to ask to JUG, thank's I've got little and expensive clue:
PropertyEditor, so here's the steps, because it make me easier when I wrote it in walktrough style :
  • I need bind the id type in initBinder method in FInancialFormController, that error says that system cannot convert String to FinancialPk type. So I add it together with Date type and numbers type.
  • Before that I need to override the getAsText and setAsText, methods from PropertyEditor.
  • First I made FinancialPk implements PropertyEditor and add those methods, and I wrote in initBinder: binder.registerCustomEditor(FinancialPk.class, new FinancialPk()); but it results an error.
  • So, I browse the net and I need new class called FinancialPkSupport that extends PropertyEditorSupport which is an adapter of PropertyEditor interface, make a constructor that have one parameter: Class pkClass. And ofcourse, override those to methods.
  • And then in inintBinder in FinancialFormController I add this line: binder.registerCustomEditor(FinancialPk.class, new FinancialPkSupport(FinancialPk.class));
Here's my FinancialPkSupport:

public class FinancialPkSupport extends PropertyEditorSupport {
private Class pkClass;

public FinancialPkSupport() {}
public FinancialPkSupport(Class pkClass) {
this.pkClass = pkClass;
}

public String getAsText() {
Object value = getValue();
return value == null ? "" : ((FinancialPk) value).dimChartaccount.getAccountKey() + "," +
((FinancialPk) value).dimCurrency.getCurrencyKey() + "," +
((FinancialPk) value).dimLocation.getLocationKey() + "," +
((FinancialPk) value).dimTime.getDimensionKey();
}

public void setAsText(String string) throws IllegalArgumentException {
FinancialPk f = new FinancialPk();
StringTokenizer token = new StringTokenizer(string);
f.setDimChartaccount(new DimChartaccount(Long.valueOf(token.nextToken(","))));
f.setDimCurrency(new DimCurrency(token.nextToken(",")));
f.setDimLocation(new DimLocation(token.nextToken(",")));
f.setDimTime(new DimTime(Long.valueOf(token.nextToken(","))));
if (f == null) {
throw new IllegalArgumentException("FinancialPk is null: " + string);
}
setValue(f);
}
}

And here's my initBinder:
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
binder.registerCustomEditor(FinancialPk.class, new FinancialPkSupport(FinancialPk.class));

SimpleDateFormat specFormat = new SimpleDateFormat(Constants.DATE_FORMAT);
binder.registerCustomEditor(Date.class, new CustomDateEditor(specFormat,true));

NumberFormat nf = NumberFormat.getNumberInstance(request.getLocale());
nf.setMaximumFractionDigits(Integer.parseInt(Constants.MAX_FRAX_DIGITS));
binder.registerCustomEditor(Double.class, null,new CustomNumberEditor(Double.class, nf, true));
binder.registerCustomEditor(Long.class, null,new CustomNumberEditor(Long.class, true));
}

And good bye frustating error!!

2 comments:

JesperBlog said...

ups, I forgot to mention site that gve me example to build FinancialPkSupport. Here's the site: http://www.ociweb.com/jnb/jnbOct2004.html

Anonymous said...

Mas, saya may tanya... saya mengalami kebingungan dengan penggunaan PropertyEditor, Saya punya sebuah kelas Desktop(Produk) yang didalamnya terdapat sebuah property dengan type data Long, nah setiap kali user memasukan input String maka saya mendapatkan output type mismatch exception, saya sdh coba dengan membuat PropertyEditor dan meregister InitBinder di Controller, kurang lebih kodenya seprty ini :

public void setAsText(String text) throws IllegalArgumentException { setValue(Long.parseLong(text));
}

@Override
public String getAsText() {
Desktop desktop = (Desktop) getValue();
return desktop.getPrice().toString();
}

sedangkan di controller nya :
@InitBinder
protected void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Desktop.class, new CustomNumberEditor(Long.class, false));
binder.registerCustomEditor(Desktop.class, new DesktopPropertyEditor());
}

Apakah jika sudah menggunakan initbinder maka tidak boleh menggunakan kelas yang mengimplementasikan validator,
Mohon pencerahannya...
Terimakasih