07/10/2008

More on Properties without Strings


What I described in my entry on the 17th was after building a proof of concept.  Now I have used this in a real live application, and filled in some of the gaps and also proved that it actually works.

Of course, as has been pointed out, this is only a place holder until Sun (or the OpenJDK community) get around to proper property support in the compiler, and I would drop this like a shot if ever it comes to pass.  

I had tried Annotations, but having to build a separate class, even if it is generated automatically, strikes me as second best.  It is actually also difficult to find the Annotations sometimes, as for instance the PropertyInfo data returned as the class of the property the return type of the getter, not the type (with annotations) of the underlying property.

This code would also be useful not just with BeanBinding (which seems about as moribund as property support), but also with JGoodies bindings, or with the UFacekit work that is being done to make JFace from Eclipse-SWT work with Swing and Qt.  But more on UFacekit later.
Read More

17/09/2008

BeansBinding and Properties without strings


It bugs me seriously that Java does not have property support.  Instead we are lumbered with coding field names as strings, which can not be checked by IDEs or compilers - back to the days of Scripting languages where the only way to debug it is to run it and watch for unexpected results.

So I went looking for a way to achive those uses of property support that are needed for BeansBinding - which is basically setup time access to field names for class members.  I looked at Annotations, and at the Bean-Properties (https://bean-properties.dev.java.net), but none did what I wanted.  Bean-Properties is really interesting, and there are only two problems with it, firstly development seems to have stopped, and secondly it does not integrate cleanly with JPA and I want to use JPA.

Java does not provide a means to express a field as anything other than a value, and every attempt to add property support to Java seems to get rubished as unnecessary, and as a polution of the language.

The basic problem is that getting back to the declaration of a value from its value is not something that Java makes easy.  Well actually stating it that way gives the clue as to how to proceed.

Now Java passes values around by reference, not by value - yes I know this is a simplification but it will do for here.  Java also has a literal pool, so constants will be references to that pool, not to unique  values.  This literal pool is used for things like String literals, and uses the fact that String values are immutable to enable this optimisation.

As I am working with BeanBinding and JPA it also makes sense to have a restriction that no native types are allowed, they must all be wrapped.  So int becomes Integer etc.

So this leads to a solution, which works for me.  Lets start with forms, i.e taking a single class object and displaying/editing fields within it.

I tend to have a single object of the relevant class, and I bind that object to the fields - or rather I bind the members of that object to the display fields.  I do this so that I can then have save and cancel buttons, and do proper logical validations before I copy the class object back to wherever it is needed.  This also means that I only do binding once, and I only do it during intialisation.

Getting from Class object (parent) to field is easy using getDeclaredFields.

As a reference is passed around we can find which field this value came from using the == operator, provided all the values are unique.  So by finding the field which contains the same value as the one we are looking for we have found our field.  So here is some static methods to find a field from an object, to find a property from an object, and find a resource (string to display) for a field in a class describing the UI.

        public static Field findField(Object parent, Object child) {
                Field[]fields = parent.getClass().getDeclaredFields();
                for(Field field: fields) {
                        try {
                                field.setAccessible(true);
                                if(field.get(parent) == child) return field;
                        } catch(Exception e) {
                                e.printStackTrace();
                                }
                        }
                return null;
                }
        public static <T> Property<T,Object> property(T parent,Object child) {
                Field field = findField(parent,child);
                if(field == null) return null;
                return BeanProperty.create(field.getName());
                }
        public static String resource(JPanel parent,String child) {
                ResourceBundle bundle = ResourceBundle.getBundle("MessageBundle");
                String value = bundle.getString(parent.getClass().getCanonicalName() + "." + child);
                if(isEmpty(value)) return child;
                return value;
                }

Now of course all of this relies on the fields all containing unique values.  You can of course do this yourself, but here is another static method which would do what is needed.  It does assume that all objects that might be in the system can be instantiated:-

        public static <T> T prepare(T parent) {
                HashMap<Object,String>map = new HashMap<Object,String>();
                Field[]fields = parent.getClass().getDeclaredFields();
                for(Field field: fields) {
                        field.setAccessible(true);
                        try {
                                Object value = field.get(parent);
                                if(value == null) {
                                        value = field.getType().newInstance();
                                        field.set(parent,value);
                                        }
                                String oldField = map.get(value);
                                if(oldField != null) throw new IllegalArgumentException( "value not unique, " +
                                                   field.getName() + " has the same value as " + oldField);
                                map.put(value, field.getName());
                        } catch(Exception e) { throw new RuntimeException("preparing object", e); }
                        }
                return parent;
                }

The glorious thing is that it works.  All that remains is a mechanism to cope with compound names.

To use this we take a class with fields we want to bind, create an instance, prepare it, and bind it to Swing components:-

   public class Contact {
      private String name;
      private String phone;
      private String email
      public String getName() { return name; }
      public void setName(String newValue) { name = newValue; }
      public String getPhone() { return phone; }
      public void setPhone(String newValue) { phone = newValue; }
      public String getEmail() { return email; }
      public void setEmail(String newValue) { email = newValue; }
      }

   public class Panel extends JPanel {
      JTextField name = new JTextField();
      JTextField phone = new JTextField();
      JTextField email = new JTextField();
      private static final Property textProp = BeanProperty.create("text");
      public void bind(Contact contact) {
         Property prop = property(contact,contact.getName());
         Bindings.createAutoBinding(UpdateStrategy.READ_WRITE, contact, prop, name, textProp).bind();
         Property prop = property(contact,contact.getPhone());
         Bindings.createAutoBinding(UpdateStrategy.READ_WRITE, contact, prop, phone, textProp).bind();
         Property prop = property(contact,contact.getEmail());
         Bindings.createAutoBinding(UpdateStrategy.READ_WRITE, contact, prop, email, textProp).bind();
               }
          }  

Look, NO Strings (apart from the text one for the JTextField)!

Please note, all code shown in this blog entry are Copyright (C) David Goodenough & Associates Limited 2008, and are licenced as LGPLV2 (please see http://fsf.org for a full copy of this licence)

28/07/2008

Installing brl-cad on a Debian system


Brl-CAD (http://brlcad.org) is a 3D CAD package created by the US Army.  It is open source, and most versions are distributed as source.

Unforuntately the ./configure script does not fully detect the libraries and paths needed, and the documentation does not seem to list it either.

So on a machine that does not have scads of -dev packages installed what are you going to need.

1) Compiler/Tools
The default Debian install does install a basic set of compilation tools, but does not install g++ or bison, or make, you will need both:-

apt-get install g++ bison make

2) -dev packages
You will need the X11 development pacakges, and one extra that the basic that does not seem to install:-

apt-get install libx11-dev libxi-dev

You will also need zlib's -dev package:-

apt-get install zlib1g-dev

3) There are options to install various extra bits, such as some Java support.  I have had the need to use these so I have not installed them yet.

I think I have remembered all of them, but I can not be sure.  

Remember when you run ./configure that it puts things by default in /usr/brlcad - a very un-Debian place.  So run ./configure as:-

./configure --prefix=/usr/local
make
make install

You may need sudo for this last step, all the others can be done as a normal user.

There is a DEB file, on the brocad web site, but it is several releases out of date, and has no dependancy checking at all, so avoid it and use the source.

23/11/2006

Running Java programs as services


Some Java code is packaged to run easily as a long running service (Tomcat for instance), but if you are writing your own code or are using code that has not been set up to run in this way it be problematic.

Fortunately TunakiSoftware have provided a solution, a wrapper that takes care of all the problems and even runs with the same config files on Windows and Linux.  It can be found at http://wrapper.tanukisoftware.org/doc/english/introduction.html.
Read More

22/11/2006

How to a missing gpg key for apt-get on Debian


If you get this warning

W: There are no public key available for the following key IDs:
A70DAF536070D3A1

when you run "apt-get update" under Debian Etch (testing) then...
Read More

10/11/2006

Windows refund?


Is this (http://www.theinquirer.net/default.aspx?article=35610) the first time that a pc supplier has refunded a user for the Micosoft Windows license pre-installed?  Why didn't they buy a PC without Windows pre-loaded? They used to be available...

07/11/2006

Day at the IBM Innovation Centre


Today IBM ran an "Update on Lotus software offerings" event for business partners at Hursley.
Read More

06/11/2006

Welcome to the new DGA Blog


Welcome to the new DGA blog.  Thanks to Declan Lynch's new BlogSphere Domino template we have brought this new resource to DGA.
Read More

Tag Cloud