Maven: Fixing table bug for site plugin 2.1

Some time ago a new big release for the site plugin has been done.
Unfortunately they have introduced a small bug:

The table tags now contain the alignment attribute set to “left”.

This results to some strange bugs. Take a look at that page:
http://fest.easytesting.org/javafx/maven/compile-mojo.html

Table Bug in maven-site-plugin:2.1

Look at the background of the table. The following h3 gets resized and its background is drawn behind the table…

To fix it, just add those lines to the CSS:

1
2
3
table {
  float: none;
}

JUnit @Theory oddities

At the moment I try to switch my tests for serialization.cedarsoft.org over to JUnit Theories (4.8.1).

And I run into some problems:

No DataPoints

1
2
3
4
5
6
7
8
@RunWith( Theories.class )
public class TheoriesTest {
  @Theory
  public void aTheory( String arg ) {
    System.out.println( "TheoriesTest.aTheory(" + arg + ")" );
    assertNotNull( arg );
  }
}

Throws an exception: java.lang.AssertionError: Never found parameters that satisfied method assumptions. Violated assumptions: []

Very nice. A theory doesn’t make any sense without any DataPoints.

A DataPoint method

Okay, now I created a DataPoints method:

1
2
3
4
  @DataPoint
  public static String getParam() {
    return "daParam";
  }

And everything works as expected.

Removing the static keyword

In my test cases I try to avoid every unnecessary key press as good as I can. Therefore I would like to create an abstract method that I just have to implement (IDE creates the method stub for me then).

So I just removed the static keyword from the method to try if it is possible…

And guess what?

The test method did not run – but is reported as succeeded…

JavaFX2Java Bridge added to JFXtras (step 2)

Thanks to Stephen: He has prepared a branch for the upcoming 0.7 release of JFXtras. Now it has been possible to merge the latest changes to the JFXtras default branch.

There are a lot of changes waiting in line. While the 0.7 release will be a huge step, I am really looking forward for 0.8…

So if you want to take a look at the latest changes, just check out the source code at http://code.google.com/p/jfxtras/source/checkout.

JavaFX2Java Bridge added to JFXtras (step 1)

It has taken a long time since I promised to integrate the JavaFX2Java bridge to JFXtras until I finally did it…

At the moment the code is located at a clone that will be integrated as soon as JFXtras 0.7 has been released.

The clone can be accessed there:
https://js-mavenization.googlecode.com/hg/

The package is named “org.jfxtras.bridge”.

JFXtras: 0.7 RC1 released

Hi guys,

the first release candidate for JFXtras 0.7 has been released. This version is (should be) fully functional with JavaFX 1.3
Downloads can be found at http://jfxtras.org/

Closing the gap between Java and JavaFX

There is a huge gap between Java and JavaFX: While it is very easy to bind JavaFX objects to each other there has been no way to bind JavaFX objects to Java properties (and vice versa).

It has taken me some time to figure out how this could be solved. And at the moment I am in the progress of adding that stuff to the JFXtras project.
This will take some time until I have taken all necessary steps.

Until then i want to give you a quick jar that can be used to try that stuff…

To try it, download that jar and add it to the classpath of your JavaFX project:
bridge-1.0.0-SNAPSHOT-jar-with-dependencies

There are two ways of synchronization. At first it is possible to listen for changes to Java objects and update an JavaFX object accordingly. At the moment I have implemented two ways to listen for updates.

Java to JavaFX

  • PropertyChangeEvents: This is the recommended way: Just make your Java bean fire PropertyChangeEvents whenever a property has changed.
  • Busy waiting: I have added a hackish way of busy waiting. This should not be used in production code. But it offers a fast way to test things

JavaFX to Java

The reverse way has also two ways implemented:

  • Calling of setters: If a JavaFX var is updated, this bridge calls the corresponding setter of your Java object (using reflection or optionally your own optimized implementation).
  • PropertyChangeEvents: It is possible to create a bridge that converts the JavaFX binding
    updates to PropertyChangeEvents.

With inverse…

Of course it is also possible (and most of the time necessary) to create bindings with inverse. I give you a small sample how this might work here:

We create our Java “model”:

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
package fxbindingtest;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class JavaClass {
  private float amount = 99;

  public float getAmount() {
    return amount;
  }

  public void setAmount(float amount) {
    pcs.firePropertyChange("amount", this.amount, this.amount=amount);
    System.out.println("Changed amount to " + amount );
  }

  final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

  public void addPropertyChangeListener( PropertyChangeListener listener) {
    pcs.addPropertyChangeListener(listener);
  }

  public void removePropertyChangeListener( PropertyChangeListener listener) {
    pcs.removePropertyChangeListener(listener);
  }
}

And here comes our JavaFX stage. This stage contains just a slider that is bound to the Java object (with inverse).
Every five seconds the model object is updated (amount+=10) – and reflected by the slider.

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package fxbindingtest;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import com.cedarsoft.fx.JavaFxBridge;
import com.sun.javafx.runtime.FXObject;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;

/**
 * @author johannes
 */

var slider: Slider;

//The java model class. Contains the property "amount" and a PropertyChangeSupport
def javaModel = new JavaClass();

Stage {
  title: "Application title"
  scene: Scene {
    width: 800
    height: 600
    content: [
      slider = Slider {
          min: 1
          max: 100
          snapToTicks: true
        }
    ]
  }
}

//Create the binding from the java model to the slider
//Using the defaults:
// Java --> FX: PropertyChangeEvents
// FX --> Java: Calling setters by reflection
JavaFxBridge.bridge( javaModel ).to( slider as FXObject ).connecting(
  JavaFxBridge.bind( "amount" ).to( "value" ).withInverse()
); //sorry for the stupid API - needs some polishing...

//Add a timeline to simulate changes to the model
Timeline {
  repeatCount: Timeline.INDEFINITE
  keyFrames: [
    KeyFrame {
      time: 5s
      action: function() {
        println("changing amount on model");
        javaModel.setAmount( javaModel.getAmount() + 10 );
      }
    }
  ];
}.play();

And here a JNLP to run the demo (open Java Console to see the updates printed to System.out):
webstart

Disclaimer:
This is just a working-in-some-situations-prototype. It is not production-ready by far.
But if you have any comments/ideas/bugs, please mail me.

The source code can be downloaded here. But I will add that stuff to JFXtras very soon…

Binding PropertyChangeSupport to JavaFX objects transparently

Binding is one of the best features in JavaFX. The possibility to class Java APIs from JavaFX is another one.
But unfortunately there is no easy way to combine JavaFX binding and Java PropertyChangeEvents. Therefore I have taken a look at the JavaFX code and I think I have found a possible solution:

The manual way

Of course you can add on replace triggers on every var and fire your events manually:

1
2
3
4
5
6
7
8
9
10
11
12
class Customer{
  public var name:String = "" on replace old {
    pcs.firePropertyChange("name", old, name );
  };
  public var address:String = "" on replace old {
    pcs.firePropertyChange("address", old, address );
  };
  public var mail:Email on replace old {
    pcs.firePropertyChange("mail", old, mail );
  };
  public-read def pcs = new PropertyChangeSupport( this );
}

This has at least three disadvantages:

  • At first your code becomes very ugly. A lot of boilerplate code without any type checking. Very easy to make faults. Very hard to find them.
  • But the second problem is even worse – if you don’t know for sure whether there is a listener registered. This approach destroys lazy binding which has been introduced in JavaFX 1.3. Every time the binding is invalidated, the replace trigger forces an update – even if nobody is registered at the PropertyChangeSupport.
  • It can’t be “attached” to existing JavaFX classes.

Using an automated bridge

I have created a bridge that can be attached to every JavaFX object. This bridge uses the JavaFX binding stuff and translates the binding updates to PropertyChangeEvents.
There is no reflection involved when vars are updated (just when setting it up). So performance shouldn’t be a problem.
(Of course this approach also prevents lazy bindings since the events have to be created every time the vars change). So only attach the bridge if it is necessary.

The bridge can be used like that:

1
2
3
 * FXObject fxObject = ...
 * Fx2PropertyChangeEvent bridge = Fx2PropertyChangeEvent.bindProperties( "name", "id" ).to( fxObject );
 * bridge.addPropertyChangeListener( "name", new PropertyChangeListener(){...} );

Of course the bridge can also be used within your JavaFX scripts/classes.

And here comes the code: Feel free to use 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package com.cedarsoft.fx;

import com.sun.javafx.runtime.DependentsManager;
import com.sun.javafx.runtime.FXBase;
import com.sun.javafx.runtime.FXObject;
import com.sun.javafx.runtime.annotation.Public;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;

/**
 * This is a bridge that connects a PropertyChangeSupport to one or more JavaFX vars.
 * <p/>
 * This bridge does use reflection only to set things up! Whenever a var is updated there no(!) reflection is used!
 * Therefore the performance is quite good.
 * <p/>
 * <p/>
 * The Code might look like that:
 * <pre>
 * FXObject fxObject = ...
 * Fx2PropertyChangeEvent bridge = Fx2PropertyChangeEvent.bindProperties( "name", "id" ).to( fxObject );
 * bridge.addPropertyChangeListener( "name", new PropertyChangeListener(){...} );
 * </pre>
 */

@Public
public class Fx2PropertyChangeEvent extends FXBase {
  @NotNull
  private final PropertyChangeSupport pcs;
  @NotNull
  private final List<Entry> entries = new ArrayList<Entry>();
  @NotNull
  private final FXObject bindee;

  public Fx2PropertyChangeEvent( @NotNull FXObject bindee ) {
    this( bindee, null );
  }

  public Fx2PropertyChangeEvent( @NotNull FXObject bindee, @Nullable PropertyChangeSupport pcs ) {
    super( false );
    this.bindee = bindee;
    this.pcs = pcs == null ? new PropertyChangeSupport( this ) : pcs;
    initialize$( true );
  }

  /**
   * Convert to property change events.
   *
   * @param propertyName the name of the property (var)
   */

  void bindTo( @NotNull String propertyName ) {
    try {
      String fieldName = "$" + propertyName;
      bindee.getClass().getField( fieldName );
    } catch ( Exception ignore ) {
      throw new IllegalArgumentException( "Invalid property name <" + propertyName + ">" );
    }

    try {
      String varNumFieldName = "VOFF$" + propertyName;
      Integer varNumField = ( Integer ) bindee.getClass().getField( varNumFieldName ).get( null );

      int index = addEntry( propertyName, varNumField );
      DependentsManager.addDependent( bindee, varNumField, this, index );
    } catch ( Exception e ) {
      throw new RuntimeException( e );
    }
  }

  @Override
  public boolean update$( FXObject src, int depNum, int startPos, int endPos, int newLength, int phase ) {
    Entry entry = getEntry( depNum );
    if ( phase == 65 ) {
      Object oldValue = src.get$( entry.getVarNumField() );
      entry.setOldValue( oldValue );
    } else if ( phase == 92 ) {
      Object newValue = src.get$( entry.getVarNumField() );
      pcs.firePropertyChange( new PropertyChangeEvent( src, entry.getPropertyName(), entry.getOldValue(), newValue ) );
    } else {
      throw new IllegalStateException( "Invalid phase: " + phase );
    }

    super.update$( src, depNum, startPos, endPos, newLength, phase );
    return true;
  }

  private int addEntry( @NotNull @NonNls String propertyName, int varNumField ) {
    int index = entries.size();
    entries.add( new Entry( propertyName, varNumField ) );
    return index;
  }

  @NotNull
  private Entry getEntry( int depNum ) {
    return entries.get( depNum );
  }

  public void addPropertyChangeListener( PropertyChangeListener listener ) {
    pcs.addPropertyChangeListener( listener );
  }

  public void removePropertyChangeListener( PropertyChangeListener listener ) {
    pcs.removePropertyChangeListener( listener );
  }

  public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener ) {
    pcs.addPropertyChangeListener( propertyName, listener );
  }

  public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener ) {
    pcs.removePropertyChangeListener( propertyName, listener );
  }

  @NotNull
  public FXObject getBindee() {
    return bindee;
  }

  @NotNull
  public PropertyChangeSupport getPcs() {
    return pcs;
  }

  public static class Entry {
    private final String propertyName;
    private final int varNumField;
    private Object oldValue;

    public Entry( String propertyName, int varNumField ) {
      this.propertyName = propertyName;
      this.varNumField = varNumField;
    }

    public String getPropertyName() {
      return propertyName;
    }

    public int getVarNumField() {
      return varNumField;
    }

    public Object getOldValue() {
      return oldValue;
    }

    public void setOldValue( Object oldValue ) {
      this.oldValue = oldValue;
    }
  }

  /**
   * Binds the given property names
   *
   * @param propertyNames the property names
   * @return the fluent factory used to create a Fx2PropertyChangeEvent
   */

  @NotNull
  public static FluentFactory bindProperties( @NotNull @NonNls String... propertyNames ) {
    return new FluentFactory( propertyNames );
  }

  /**
   * Binds the given property names
   *
   * @param propertyNames the property names
   * @return the fluent factory used to create a Fx2PropertyChangeEvent
   */

  @NotNull
  public static FluentFactory bind( @NotNull @NonNls String... propertyNames ) {
    return bindProperties( propertyNames );
  }

  /**
   * Fluent factory implementation
   */

  public static class FluentFactory {
    @NotNull
    private final String[] propertyNames;

    private FluentFactory( @NonNls @NotNull String[] propertyNames ) {
      //noinspection AssignmentToCollectionOrArrayFieldFromParameter
      this.propertyNames = propertyNames;
    }

    /**
     * Binds the property names to the given bindee
     *
     * @param bindee the bindee the properties are bound to
     * @return the bridge
     *
     * @noinspection InstanceMethodNamingConvention
     */

    @NotNull
    public Fx2PropertyChangeEvent to( @NotNull FXObject bindee ) {
      if ( propertyNames.length == 0 ) {
        throw new IllegalArgumentException( "Need at least one property to bind to" );
      }

      Fx2PropertyChangeEvent bridge = new Fx2PropertyChangeEvent( bindee );
      for ( String propertyName : propertyNames ) {
        bridge.bindTo( propertyName );
      }
      return bridge;
    }
  }
}

/**
 * Copyright (C) cedarsoft GmbH.
 *
 * Licensed under the GNU General Public License version 3 (the "License")
 * with Classpath Exception; you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *         http://www.cedarsoft.org/gpl3ce
 *         (GPL 3 with Classpath Exception)
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3 only, as
 * published by the Free Software Foundation. cedarsoft GmbH designates this
 * particular file as subject to the "Classpath" exception as provided
 * by cedarsoft GmbH in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 3 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 3 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact cedarsoft GmbH, 72810 Gomaringen, Germany,
 * or visit www.cedarsoft.com if you need additional information or
 * have any questions.
 */

I will upload a complete project very soon (Monday). This will contain several samples and unit tests….

JavaFX Internals Part 2

Yesterday I wrote about some JavaFX Internals…. Today comes the second part.

Today we start to use some of the JavaFX classes by Java. Therefore I just added all JavaFX jars to the classpath.

Extending FXBase

It is a very good idea to extend FXBase. We just have to figure out which methods have to be called for initialization. Following the samples, our class could look like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.sun.javafx.runtime.FXBase;
import com.sun.javafx.runtime.FXObject;
import com.sun.javafx.runtime.annotation.Public;


@Public
public class Run extends FXBase implements FXObject {
  public static void main( String[] args ) {
    System.out.println( "Starting!" );

    System.out.println( "Finished" );
  }

  public Run() {
    this( false );
    initialize$( true );
  }

  public Run( boolean paramBoolean ) {
    super( paramBoolean );
  }
}

Approaching that binding stuff

As mentioned yesterday the magic happens within the DependentsManager. Thankfully that sources are available…
One key is the WeakBinderRef that can be stored within each FXObject and be retrieved calling getThisRef$internal$().
There is a static method that creates those refs lazyly: WeakBinderRef.instance().

This WeakBinderRef contains the dependencies for this object. The field bindees contains a chain of Dep instances. Interestingly the WeakBinderRef for test does not contain any bindees as one might have expected. Those are the reverse dependencies!

The “real” dependencies are stored within each object within the field DepChain$internal$ (of type DepChain).
Relevant is the bindeeVarNum. Here is the var num stored that dependency is based upon.

Process of dependency notification

Whenever a var is changed, there are two calls made to notifyDependents$. They can be distinguished by the phase (argument).
That methods uses the DependentsManager to call invalidate on all depending objects. Those simply change the flag so that the next time the var is accessed, it can be resolved again.

While the binding performance in JavaFX is much better in 1.3 it is still not really lazy. There happen a lot of calls until the value is marked as invalid.
So I assume that the performance has just been increased for complex binding expressions. Just binding one var to another shouldn’t be much faster now (this is just an assumption!)…

Adding dependencies manually

Now we try to add a dependency manually. It is possible by simply calling “DependentsManager.addDependent()“.
Of course it does not have any visible effects (besides that the update/invalidate methods are called). Because the values are fetched from the original objects… But the debugger shows us, that it is possible to use that bind mechanism from Java.

Analyzing JavaFX

Today I wanted to analyze the internals of JavaFX. This post is the documentation – primarily made for myself. But maybe useful for somebody else, too…

Simple class

At first I tried to create a simple class with just one var of type String:

1
2
3
public class Test{
  var value:String = "asdf";
}

And then I tried to take a look at the internals. Of course I did not decompile that stuff. Instead I used javap and Reflection to analyze it myself. The result could look like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.sun.javafx.runtime.FXBase;
import com.sun.javafx.runtime.FXObject;
import com.sun.javafx.runtime.annotation.Public;
import com.sun.javafx.runtime.annotation.ScriptPrivate;
import com.sun.javafx.runtime.annotation.SourceName;

@Public
public class Test extends FXBase implements FXObject {
  @ScriptPrivate
  @SourceName( "value" )
  private String $value;

  public Test() {
    this( false );
    initialize$( true );
  }

  public Test( boolean paramBoolean ) {
    super( paramBoolean );
    this.$value = "asdf";
  }
}

So, what is interesting about this?
At first the name of the field is not so nice. Very hard to access using Reflection… But probably that is intended.
Every JavaFX class extends FXBase (or implement FXObject if extending another Java class).

Well, those information can be found within the sources of FXBase (look at src.zip)…

Changing var to def

What is the difference? There is just an annotation (@Def) added to the field…
Read more

JavaFX Bug or Feature? Panel doesn’t layout if placed in class

I run into a strange problem. I think I have missed something. So every hint is welcome!

Try this demo:

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
36
37
38
39
40
41
42
43
44
45
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Panel;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;
import javafx.scene.layout.Container;

public function run(   ) {

  //Remove the next two lines for a miracle!
  Asdf {}}
public class Asdf {

  def stage: Stage = Stage {
      scene: Scene {
        width: 800
        height: 600
        content: [
          {
            def p: Panel = Panel {
                width: bind stage.scene.width
                height: bind stage.scene.height
                onLayout: function (): Void {
                  p.resizeContent();
                  for ( node in Container.getManaged( p.content ) ) {
                    Container.positionNode( node, indexof node * 20 + 50, indexof node * 30 + 40, true );
                  }
                }
                content: [
                  Rectangle {
                    width: 140, height: 90
                    fill: Color.ORANGE
                    opacity: 0.5
                  },
                  Rectangle {
                    width: 100, height: 120
                    fill: Color.BLUE
                    opacity: 0.5
                  }, ]
              }
          },
        ]
      }
    };
}

The layout of the panel doesn’t work properly…

Now lets move the stage directly into the run function (just remove two lines):

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
36
37
38
39
40
41
42
43
44
45
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Panel;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;
import javafx.scene.layout.Container;

public function run(   ) {

  //Remove the next two lines for a miracle!
  //Asdf {}}
//public class Asdf {

  def stage: Stage = Stage {
      scene: Scene {
        width: 800
        height: 600
        content: [
          {
            def p: Panel = Panel {
                width: bind stage.scene.width
                height: bind stage.scene.height
                onLayout: function (): Void {
                  p.resizeContent();
                  for ( node in Container.getManaged( p.content ) ) {
                    Container.positionNode( node, indexof node * 20 + 50, indexof node * 30 + 40, true );
                  }
                }
                content: [
                  Rectangle {
                    width: 140, height: 90
                    fill: Color.ORANGE
                    opacity: 0.5
                  },
                  Rectangle {
                    width: 100, height: 120
                    fill: Color.BLUE
                    opacity: 0.5
                  }, ]
              }
          },
        ]
      }
    };
}

Now everything works as expected! Any hints?

Return top
 
12 visitors online now
12 guests, 0 members
Max visitors today: 19 at 06:08 am CEST
This month: 24 at 07-06-2010 06:16 pm CEST
This year: 54 at 05-11-2010 04:53 pm CEST
All time: 54 at 05-11-2010 04:53 pm CEST

Switch to our mobile site