JavaFX and custom controls

There are two ways how a custom control/node can be created. The simple way is to extend CustomNode. Then everything should work as expected.

The second possibility is to extend Control, Skin and Behaviour. This is the better way if you want to support different skins. And of course it seems to be the more MVC-like approach. Therefore I decided to try it that way…

Problems with the *bounds*

Implementing a new control seems to be very straight forward. Just follow the examples found everywhere. But if you try to use your newly created component, you probably be surprised…

If placing the control within a Stack, the control sticks to the upper left corner. It is not layouted as I expected. During debugging I realized that the layoutBounds look strange. They are not bound to the node created by the skin. Instead they seem to be hardcoded to 0/0/100/50.

But boundsInLocal seems to be okay…

Finding the reason..

So what can we do? Just taking a look at the source code of Control should be enough… But those sources are not available!

Okay, let’s find out on our own. I created a small scene containing a Stack with its width/height bound to the scene dimensions (800/600). That stack contains the custom control.

Step 1: Simple Control without any Skin

I created a control and I did not set a skin. What happened?

As expected, the layoutBounds and the boundsInLocal where both set to (0/0/0/0).

Step 2: Simple Control with an empty Skin

I now set a skin in create() of my Control. The skin does not do anything (node is null). Result?

The layoutBounds are initially set to (0/0/100/50)!
They are then adjusted to the size of the Stack (as expected?). The layoutBounds seem to be bound to width/height of the control, as expected when reading the jfxdoc for Resizable.
The boundsInLocal stay at (0/0/0/0).

Conclusion:

There exist hard coded default values for each control (100/50). Those are used for the inital layoutBounds and the prefWidth/Height.

Step 3: Skin containing just a Rectangle

The skin assigns a Rectangle {width:70 height:150} to the node in init.

The layoutBounds didn’t change: (0/0/800/600) – influenced by the Stack size. But the boundsInLocal are now calculated correctly based on the rectangle: (0/0/150/70).

The Rectangle is now painted in the upper left corner of the stack. This is not surprising since the Stack expects the Control to be much bigger (800/600).

The prefWidth/Height returns also the hard coded values of 50/100.

Conclusion:

The boundsInLocal are bound to the node created by the skin automatically. But the layoutBounds are bound to the width and size inherited by Resizable (correctly following the documentation). But there is missing a connection between the layoutBounds of the control and those of the node created by the skin.

Additionally the prefWidth/Height and min/max methods have to be connected to the skin.

Step 4: Create custom maxWidth/Height methods

The skin overrides the maxWidth/Height methods and returns 340/320. Since the control delegates to the skin the control don’t have to be modified.

The Stack now resizes the control to its maximum width/height. Therefore the control has a size of 340/320 that are reflected by the layoutBounds. The boundsInLocal stay at the “real” size of 150/70.

The positioning of the control is different now. The stack uses the changed layoutBounds for its calculations. Therefore the rectangle has been moved towards the center. But it is still not at the center (because the layoutBounds are larger than the drawn rectangle).

Resizing the scene changes the actual width/height and layoutBounds of the control. But of course the Rectangle keeps its size.

Step 5: Implement  minWidth/Height methods

Those methods return a minWidth/Height of 50/70.This does not have any effects. The Stack seems to ignore them. So the actual size of a control may become smaller than the values returned by the min-methods.

Step 6: Bind the Rect width/height to control.width/height

Since the control is resizable we bind the width/height of the Rectangle to the width/height of the control (that is modified by the Stack).

The control has the size of 340/320 (provided by getMaxWidth/Height). The rectangle has the same dimensions and therefore is placed at the center of the Stack.

The layoutBounds and the boundsInLocal are the same now. Resizing works as expected.

Step 7: Fixing getPrefWidth/Height

Now we want to adjust the preferred width and height. Therefore we override those methods. It is probably a good idea to delegate those requests to the skin… For now those methods return 110/90.

When the control is placed within a Group, the preferred size and with is used. Since the Group is not resizable the Stack can’t change the size.

The control is layouted with its preferred size in the center of the Stack.

[JavaFX] Bind bug? Or am I just stupid?

I really love that binding stuff in JavaFX. I am looking forward until some smart guy implements something similar in Scala…

But I also have some problems with it. Sometimes “on replace” triggers are called with the same values for <old> and <new>. Here is a small sample script that shows it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.lang.RuntimeException;

/**
 * @author johannes
 */

println( "Starting binding test..." );
var i = 0.5 on replace old {
    println( "i changed to <{i}>" );
    if ( i == old ) {
      throw new RuntimeException( "This will never happen!" );
    }
  };
var b = bind calc( i ) on replace old {
    println( "b has changed from <{old}> to <{b}>" );
    if ( b == old ) {
      println( "!!!!!!!!!!!!!!!!!!!!!!!" );
      println( "Why is on replace called? Both objects are the same: {isSameObject( b, old )}" );
      println( "!!!!!!!!!!!!!!!!!!!!!!!" );
    }
  };

println( "i: {i}" );
i = 0.5;

println( "i: {i}" );
i = 0.9;

println( "i: {i}" );
i = 1.0;

println( "i: {i}" );

function calc( i     ) {
  return i < 1;
}

Of course I have posted a question in the JavaFX forum. But no answers yet….

UPDATE:
Has finally been fixed in 1.3! Now it works as expected.

cedarsoft Serialization 1.0.0 released

cedarsoft Serialization (GPL with Classpath Exception) offers version aware serialization of java object trees with maximum control. Its goal is to provide some simple classes (very small framework) that enables rapid development of versioned serialization.

Serialized XML contains version informations and might look like that:

<?xml version="1.0" encoding="UTF-8"?>
<businessObject xmlns="http://yourcompany.com/path/2.0.1">
  <name>theName</name>
  ...
</businessObject>

It does not contain any “magic” code. It just offers plain and very fast serialization.

It follows those main ideas:

  • Version support as first class citizen (Every serialized object gets its version information attached –>necessary for stability)
  • Minimized boiler plate code (–> fast results), but:
  • No magic (no bad surprises)
  • KISS
  • Performance, performance!
  • Flexibility and therefore stability: Serialized objects can be read with all future versions.

Do not believe the wrong “everything can be done automatically” promise. Write that code that matters. And nothing more.

Don’t miss the revolution…

Evolution happens

Evolution happens. All the time. Evolution is sloooow. And it is easy to adjust to evolution. You have to change (yourself, your behaviour, your habit). But just a little bit. Maybe tomorrow a little bit, too. But that is not a problem. Because evolutionary change happens so slowly that even the most “retracted person” is able to follow.

And evolution improves the current state with minimal side effects and disadvantages.

Micro-Evolution

It is an easy step to upgrade your IDE. Eclipse 3.5 SR1 has been released? Just download and install that version. Some paranoid guys will just sit and wait a few days/weeks, and maybe run a few tests. But then they will update easily (and be happy).

Sun releases a bugfix version of the JDK? Propably a drop-in replacement.

Local Maximum

Local Maximum

The big step?

Evolution is great to find the local maximums without big risks. Small improvements are great. And they will improve technology. But evolution is not able to take the big step. The big step that vanquishes the current limits.

Sometimes revolution is necessary

To really improve technology it is necessary to take that big step. Sometimes it is necessary to introduce a new way things work. And to break limits everyone has accepted as God-given.

Breaking those limits opens wide space for major improvement. But is is not free. It takes a considerable amount of time and effort.  But the outcome is worth it…

Breaking the limits is hard

It is hard to break those limits. We have grown up with them. We respected them every day. We adjusted our workflows. We adjusted our mindset. And suddenly, we have to realize that we fooled ourselves for years…

Looking foolish

Mahatma Gandhi summarizes about his revolution:

First they ignore you, then they laugh at you, then they fight you, then you win.

Those that fight the revolution too long, look crestfallen at the end. But – more important in our context of technology – they have lost a lot of time and opportunities. And it will take a big effort to catch up with those who have recognized the new possibilities earlier.

Be warned…

Some of the most intelligent and successfull people on that planet missed the biggest revolutions related to technology. Just think of Bill Gates and his first thoughts about that “Internet thing”…

To be continued…

Top 10: Why Subversion is better than Git

[Update:

I have received a lot of attention. Thanks for that. But obviously not everybody has detected the unobtrusive irony this article might contain...

So please reread this article one more time before you:

  • Link this article to your Subversion-Blog
  • Try to convert me to Git
  • Use the arguments in a real discussion

But the reactions I received, prove that I have mimicked some *real* opinions very well. And that really makes me sad...]

There are many blog posts out there that try tell you why Git is better than Subversion. But very few that tell you why Subversion is better that Git. As expected: You don’t have to state the obvious…

1. It is industry standard

Subversion is more widely spread and better known.

And it is a good idea for every business to rely on the “industry standard”. Therefore it is strongly recommended to use CVS (the real industry standard) or at least Subversion. But please stay with version 1.4. That one is well tested. And the new stuff probably has many bugs that just wait to purge your repository (and all backups).

Prove: Just compare the frequency of releases

The last CVS releases have been 1.11.22 on 2006-06-09 and 1.11.23 on 2008-05-08.
Subversion releases a new version about every two or three months (1.6.6 on 10/22/2009, 1.6.5 on 08/22/2009).
But Git: They release new versions every few days! They have so many bugs and so few features that they are forced to release even the smallest improvements immediately…

Remember: Fewer releases represent greater stability and more features.

2. Central Repository

Subversion has a central repository. That is what everybody wants. Every manager wants to know where the code lives. With subversion you can take his hand, guide him to the server room and point to the server.
That is what managers want.
That fancy “everybody has the complete repository” is not a work flow – it is communism…

Distributed Version Control System”

That sounds like some alternative to BitTorrent. I don’t support pirating!

3. Subversion is easy to use

The developers I have met so far, don’t understand complicated (read “command line”) tools. I don’t have to talk about web designers or sales people here…

Subversion has a nice UI (Tortoise SVN). The developers can use that UI. And they don’t have to understand the complex mechanisms of VCS. Just a click here and there is enough (see “Branches are evil” for more details).

If a problem occurs:

4. Subversion supports a single strategy that solves all problems

And if any problems occurs, those can easily be solved in Subversion: Just copy your modified files away, make a clean checkout and merge the files back manually.

That is all. No fiddling with branches, command line and such stuff.

5. Branches are evil!

Forget about creating branches (or – even more dangerous – merging). Branches are just useless and a sign that your team is not coordinated well.

Have to do critical stuff on the trunk (e.g. performing a release)? Just shout to your colleagues to stay away from the repository. Development may continue locally. And if the things take a little longer – no problem – the bigger their commits are, the better.

Maintenance branches? Come on. Have you ever seen us releasing a service release? And if really necessary: The forward-looking developer keeps a directory on his hard drive containing the sources the release has been build from.

6. Empty directories may be added

I really love organization. And I hate one thing: Anarchism. Anarchism and communism. Okay, I hate two things: Anarchism and communism. And bleeding edge…

And Subversion allows me to create a good and clean and complex directory structure. And commit it. And then check it out again. The directory structures I create usually are so helpful that everybody *must* see them immediately – just as inspiration.

7. The help is clear(er) and *much* shorter

Just compare the help pages for “svn log” and “git log“.

While Subversion just needs one page to document all features, the git documentation is insane long… Git is much more complicated. Even such a simple command needs hours to just read the documentation.

I’d go as far and say, that it is impossible to use Git without professional training of at least several days. And that is the hole point of that OpenSource/communism stuff: They try to cheat you to book expensive training…

8. Supports file locking

Do you miss the times of VSS, too?

I really hate that situation: I try to commit and have to notice that someone else has changed the file I worked on. This is ridiculous. Why should a colleague be allowed to change a file, *I* am working on?

So Git guys: First solve the locking issue and then come back.

9. Expandable keywords

I really love expandable keywords. In the old CVS days that has been my favourite feature. Okay, I don’t have a real use case, but I love to see the the magic happen.

10. Merges are forced immediately

Yeah. The killer feature of subversion.

I have to admit that maybe file locking is not the solution for every case. But at least each developer has to be forced to merge all changes before he is allowed to commit.

I hate those guys that work all day long and then try to commit their changes just seconds before they leave. And – additionally – they are very focused when they merge changes to their uncommited work. Knowing that each step might destroy the work of several hours is a great motivation.

This feature often leads to check in races. The first commiter wins, the second one has to merge. And that is worth cash: Developers are motivated to work as fast as possible.

And one more thing I love: If you are leading the check-in race, you can keep your colleague merging for a long time. Commit – file has changed in repository – update – merge – trying to commit – file has changed in repository… I could do that all the day…

Conclusion: Subversion unifies a team

Disclaimer: I really like Subversion. I have used it for several years. And I know branching has been improved dramatically in version 1.5. So this post is not a rant about Subversion but instead about those people that refuse to take the next step. Those people that prefer CVS over SVN, SVN over any DCVS and so on…

Google Collections released (finally)

After a long way, Google Collections 1.0 has been released:

Ready to be used with Maven:

<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0-rc5</version>
</dependency>

Great. I think this will become a default dependency for many projects…

Generics and Wildcards: Part 1

Wildcards have been introduced to Java some years ago (in JDK 1.5). And they are easy to understand – as long as no collections are involved. Then everything becomes a little bit more complex…

This (and the following) blog posts will try to show in simple steps how to handle wildcards in collections correctly.

Collections + Generics = non intuitional

Every Java developer knows that an Integer is also a Number since Integer extends Number. So every time someone expects a Number (e.g. as method or constructor parameter), I may call the method with a parameter of type Integer (or Double, or…).

Every time I say Number, I literally mean:
An object of type Number or of any other class extending Number.

And every Java developer is used to understand it this way (ok, there might be some that don’t, but hey, those won’t read that blog post…).

When it comes to collections, most of the Java developers unconsciously transfer that understanding. At first glance it seems to be the same thing…
Set extends Collection: So when a method parameter is declared as Collection, it might be called using a Set (or List, or…).

Collections and their content

But collections don’t just have a type. They also contain objects. And those objects also have a type. And that is the point where the trouble begin. The first step seems to be very obvious.

List<Integer> is just a List containing Integers. List#add accepts an Integer, List#get returns an Integer

And of course the same can be said about a List of Numbers:

List<Number> is just a List containing Numbers. List#add accepts a Number, List#get returns a Number

The difference between a List<Integer> and List<Number> is, that the former may contain just Integers (and sub types) while the later might contain also Doubles, Longs and so on.

Collections: The difference

Following the usual experience, one might think, that that assignment works:

1
2
List<Integer> integerList = new ArrayList<Integer>();
List<Number> numberList = integerList; //!!!! Does not work !!!!!

This assignment shouldn’t be problematic concerning read access. Every read access should return one or more Integers. And since Integer extends Number everything seems to be ok.

1
2
3
List<Integer> integerList = new ArrayList<Integer>();
List<Number> numberList = integerList; //!!!! Does not work !!!!!
Number n = numberList.get(0); //works

But what’s about write access?

The compiler allows you to add any object of type Number to be added to numberList (List<Number>). But of course it must not be possible to add an object of type Number to List<Integer>.

1
2
3
List<Integer> integerList = new ArrayList<Integer>();
List<Number> numberList = integerList; //!!!! Does not work, because of next line!
numberList.add( new Double(2.0 )); //We add a double to List<Integer>!!!!

Fruits…

A list of fruits may contain all kinds of fruits. Apples, strawberries and so on. A list of apples may only contain apples. Therefore a list of apples must never be cast to List<Fruit>.

The solution (at first non intuitional, too)

Some smart minds at Sun discovered that problem. And they also introduced the solution: Wildcards. Just accept wildcards as necessary – because they are.

First the example:

1
2
3
4
List<Integer> integerList = new ArrayList<Integer>();
List<? extends Number> numberList = integerList; //Works!
Number n = numberList.get(0); //works, since every Integer is also a Number
numberList.add( new Double(2.0 )); //Compiler error!!!

We may assign List<Integer> to List<? extends Number> since Integer extends Number.

The declaration List<? extends Number> may be read as: A list of an unknown subtype of Number.

Of course read access is possible. We now that the containing elements must be of type Number. But adding is not possible since the exact type of the list is unknown.

What’s wrong with XStream and similar tools?

Do you know XStream? It is a very famous, “magic” XML serialization framework.

It simply serializes an object tree using reflection. As default it uses the fully qualified names to be able to deserialize it later. But you can easily add aliases to tweak the XML.

The last project I worked for, used XStream very intensive. And it seems to be such a good choise. It is mature, well tested and simply does what you want.
And yes – I don’t know any other tool that offers such a good result out of the box with only very little work (”magically”).

I am sure there are several use cases where XStream is just great and does exactly the job. But sometimes XStream is the wrong choice. And it is hard to identify those situations. I personally have chosen the wrong tool for the job a few times. So here comes a simple don’t related to XStream.

XStream must not be used for mid/long term serialization.

In the project I have worked on, we used XStream to serialize settings to the file system. That really worked well. But one day we have to ship the next release of your software. And we will have to support the old  settings file…

XStream offers some support for refactorings (aliases can help). But very soon you will run into big troubles and will have to make some decisions. Either avoid refactorings (just a little tweak here and there, will weaken your architecture over time) or start implementing workarounds – e.g. custom converters (much work, bad code).

I think for mid/long term serialization it is absolutely necessary to add version information to those files. And it is absolutely necessary to handle that information correctly on deserialization. This opens the door for all kind of improvements and refactorings. You will always be able to identify the version of the serialized object (no wild guesses depending on some attributes anymore) and convert them accordingly.

Your serialization code will been kept clean. Legacy support is clearly separated…

And that leads to cedarsoft Serialization. More details will follow…

cedarsoft Serialization 1.0.0-beta1 released

cedarsoft Serialization (GPL with Classpath Exception) offers version aware serialization of java object trees with maximum control. Its goal is to provide some simple classes (very small framework) that enables rapid development of versioned serialization.

Serialized XML contains version informations and might look like that:

<?xml version="1.0" encoding="UTF-8"?>
<?format 2.0.1?>
<businessObject>
  <name>theName</name>
  ...
</businessObject>

It does not contain any “magic” code. It just offers plain and very fast serialization.

It follows those main ideas:

  • Version support as first class citizen (Every serialized object gets its version information attached –>necessary for stability)
  • Minimized boiler plate code (–> fast results), but:
  • No magic (no bad surprises)
  • KISS
  • Performance, performance!
  • Flexibility and therefore stability: Serialized objects can be read with all future versions.

Do not believe the wrong “everything can be done automatically” promise. Write that code that matters. And nothing more.

Why you should only return Collections with bounded wildcards

My post yesterday did not receive much compliance.

Many agreed, that collections with wildcards are usefull as method parameters, most deny their value as type for return values

That’s why I have created a small example that displays the problems not using wildcards. Unfortunately these problems are not very obvious and appear late. Besides that, most of the time the caller has to puzzle with it and maybe you will never hear about it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface TightList<E> {
  List<E> getIt();
}

final TightList<Integer> integerList = new TightList<Integer>() {
  public List<Integer> getIt() {
    return new ArrayList<Integer>();
  }
};

final TightList<Double> doubleList = new TightList<Double>() {
  public List<Double> getIt() {
    return new ArrayList<Double>();
  }
};


TightList<Number> wrapping = new TightList<Number>() {
  public List<Number> getIt() {
    if ( someFancyCondition ) {
      return doubleList.getIt(); //Compiler error
    } else {
      return integerList.getIt(); //Compiler error
  }
  }
};

I think it is quite obvious what happens here.

We have a simple interface called “TightList” that returns a collection without bounded wildcard. I created three implementations. The first two of them are straight forward – no problems occur here.

But the third one becomes critical. Wrapping the other TightLists is not possible.

Conclusion

There is at least one case, where returning collections without wildcard, is problematic.
Please, oblige the users of your API and add those wildcards (at least when the collection is unmodifiable – and it really should be).

Return top
 
8 visitors online now
0 guests, 8 bots, 0 members
Max visitors today: 11 at 01:53 am CEST
This month: 13 at 09-05-2010 05:29 am CEST
This year: 97 at 08-05-2010 02:42 pm CEST
All time: 97 at 08-05-2010 02:42 pm CEST

Switch to our mobile site