Year: 2014

Remember: use createInsert with af:table!

I came across this issue (again) yesterday, so I think it is worth to quickly outline it here: Oracle ADF provides two operations on a data collection to create new records, that is create and createInsert. When searching through the documentation, it turns out that the differences are:

  • create
    Opens a slot for a new record in the collection, before the current record. The new record is not added to the collection immediately (as part of the create operation itself), but only after the page has been submitted. The advantage is that no empty, orphaned record is left behind when the user navigates away from the page, without submitting it.

  • createInsert
    This is the same as create, but the new record is added to the collection immediately, as part of the createInsert operation itself.
In other words, after the http request corresponding to the create operation has finished, the collection does not contain a new record – the “new” record is maintained by the ADF framework as a temporary object in the background, until the page is submitted. On the other hand, when using the createInsert operation, then the collection does contains the new record when the http request has returned. This makes a big difference when inserting a row into an af:table component: the af:table requires that the new record is available in the collection in order to render it, otherwise no new row will be visible. So, while create can still be used with forms, make sure that you always use createInsert when adding new rows to an af:table! There is a nice article by Andrejus Baranovski which describes this in more detail: ADF Create and CreateInsert Operations for ADF Table.

Using Lambdas to implement a function table

When I implemented an expression parser for arithmetic expressions (such as t*x+sin(x-5) + π), one part was to create a symbol table to look up constant values such as π, variables such as x and t, but also functions like sin(x). My initial approach had this structure:

 

This allowed me to create a symbol table as a HashMap, and then to add variables, constants or functions into the table:

private Map<String, Symbol> table = new HashMap<>();
...
table.put("sin",  new SinFunction());
table.put("log",  new LogFunction());
...

This works well, but requires a whole new class for each new function, where each of the classes simply provides a getValue() method which delegates to the corresponding static method from Math:

public double getValue(double arg) {
   return Math.sin(arg);
}

Using lambda expressions, the class structure can be much simplified:

Instead of an abstract class Function with specific sub classes which implement the getValue() method, we provide a concrete Function class which delegates to the functional interface DoubleFunction. The instantiation of the Function objects can then be moved into the SymbolTable class, essentially as a convenient method:

public void putSymbol(String name, DoubleFunction<Double> fun) {
   table.put(name, new Function(name, fun));
}

Now, adding new function to the symbol table is straight forward, using a lambda expression:

symbolTable.putSymbol("sin", x -> Math.sin(x));
symbolTable.putSymbol("log", x -> Math.log(x));

Especially we do not need to add another class when adding a new function. The class structure of the symbol table remains stable, all we need is to register the new function through a call to SymbolTable.putSymbol(). Besides simply mapping a function name to a method from the Math class, this works equally well for any user defined function, for example:

symbolTable.putSymbol("f1", x -> x*x + 42*x + 19);
symbolTable.putSymbol("f2", x -> Math.cos(x*x) + 42*x);

Since the Function class holds a reference to the lambda expression through the DoubleFunction interface, we simply call the DoubleFunction.apply() method to evaluate the function for a given x value:

public class Function extends Symbol {

   private DoubleFunction<Double> theFunc;

   ...

   @Override
   public double getValue(double x) {
      return theFunc.apply(x);
   }
}