Extreme Java When vanilla Java is not enough

15Dec/090

File attributes on layer.xml

When registering files on NBM's layer file, you can define attributes, too:

<file name="my-pkg-MyClass.instance">
  <attr name="mystr" stringvalue="value"/>
  <attr name="myint" intvalue="1"/>
  <attr name="mymethod"
    methodvalue="my.pkg.MyClass.myMethod"/>
</file>

They are avaliable as attributes of FileObject (through getAttribute). You can also use special attributes "instanceClass" to define a different class to instantiate or "instanceCreate" to define a factory method. This factory method can receive a map of attributes. I'm using it to customize a generic DataLoader:

public class MyLoader extends MultiDataLoader {
  private MyDataLoader(String secondaryExt) {
    super("MyObject");
    this.secondaryExt = secondaryExt;
  }
  public static build(Map<String, Object> attrs) {
    return new MyLoader(attrs.get("ext").toString());
  }
  ...
}
18Sep/090

Copying html attributes on Lift bindings

Since Java and Scala are complementary, I will post Scala-related stuff here, too (without creating a new blog).

Today's tip refers to Lift (Scala's JavaEE/Rails/Grails/Django). Suppose your webdesigner gives you this XHTML:

<input type="text" class="x" style="width: 100px;"/>

When you bind this using Lift, one of possible solutions is surround it with a tag:

<mybind:myfield><input type="text" class="x" style="width: 100px;"/></mybind:myfield>

Please notice I put it without spaces or newlines between "mybind:myfield" and "input" - this will be important later.

I prefer this way because this XHTML can be opened in other applications, like Firefox and Dreamweaver, making life easier for the webdesigner.

Then, if I bind it using old mama's recipe:

bind("mybind", form, "myfield" -> myfield.toForm)

Lift will remove my "input" tag and replace it - destroying "class" and "style". To solve this, I merge "toForm" tag with original attributes:

def merge(form : => Box[NodeSeq])(input : NodeSeq) : NodeSeq = {
  var in = input.first
  var attrs = form.open_!.first.attributes
 
  new Elem(in.prefix, in.label,
      in.attributes append attrs,
      in.scope, Group(in.child))
}
bind("mybind", form,
    FuncBindParam("myfield", merge(myfield.toForm)))

Function "merge" takes the form and returns a function that receives the original XHTML and translates it into XHTML with Lift's attributes ("id", "name", "lift:gc", etc). I guess I can improve it somehow, but works great. And, since I'm keeping only the first child of source XHTML, you need to keep "bind" and "input" together (as I said before).

I know I can use a map function to ignore whitespaces, but I'll leave it as an later exercise (for you and for me, too).