You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2009/05/06 23:24:54 UTC

svn commit: r772431 - in /incubator/pivot/trunk: tutorials/src/pivot/tutorials/ tutorials/src/pivot/tutorials/drawing/ tutorials/src/pivot/tutorials/stocktracker/ wtk/src/pivot/wtk/media/drawing/ wtk/src/pivot/wtkx/

Author: gbrown
Date: Wed May  6 21:24:48 2009
New Revision: 772431

URL: http://svn.apache.org/viewvc?rev=772431&view=rev
Log:
Add resource/locale support to WTKX binding; ensure that runtime binding binds to entire class hierarchy.

Modified:
    incubator/pivot/trunk/tutorials/src/pivot/tutorials/Demo.java
    incubator/pivot/trunk/tutorials/src/pivot/tutorials/drawing/RotateLine.java
    incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/StockTracker.java
    incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/stocktracker.wtkx
    incubator/pivot/trunk/wtk/src/pivot/wtk/media/drawing/Group.java
    incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java
    incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java

Modified: incubator/pivot/trunk/tutorials/src/pivot/tutorials/Demo.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tutorials/src/pivot/tutorials/Demo.java?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/tutorials/src/pivot/tutorials/Demo.java (original)
+++ incubator/pivot/trunk/tutorials/src/pivot/tutorials/Demo.java Wed May  6 21:24:48 2009
@@ -140,20 +140,20 @@
 
     private Window window = null;
 
-    @Load("demo.wtkx") private Component content;
-    @Bind(resource="content") private Rollup buttonsRollup;
-    @Bind(resource="content") private Rollup listsRollup;
-    @Bind(resource="content") private Rollup textRollup;
-    @Bind(resource="content") private Rollup calendarsRollup;
-    @Bind(resource="content") private Rollup navigationRollup;
-    @Bind(resource="content") private Rollup splittersRollup;
-    @Bind(resource="content") private Rollup menusRollup;
-    @Bind(resource="content") private Rollup metersRollup;
-    @Bind(resource="content") private Rollup spinnersRollup;
-    @Bind(resource="content") private Rollup tablesRollup;
-    @Bind(resource="content") private Rollup treesRollup;
-    @Bind(resource="content") private Rollup dragDropRollup;
-    @Bind(resource="content") private Rollup alertsRollup;
+    @Load(name="demo.wtkx") private Component content;
+    @Bind(property="content") private Rollup buttonsRollup;
+    @Bind(property="content") private Rollup listsRollup;
+    @Bind(property="content") private Rollup textRollup;
+    @Bind(property="content") private Rollup calendarsRollup;
+    @Bind(property="content") private Rollup navigationRollup;
+    @Bind(property="content") private Rollup splittersRollup;
+    @Bind(property="content") private Rollup menusRollup;
+    @Bind(property="content") private Rollup metersRollup;
+    @Bind(property="content") private Rollup spinnersRollup;
+    @Bind(property="content") private Rollup tablesRollup;
+    @Bind(property="content") private Rollup treesRollup;
+    @Bind(property="content") private Rollup dragDropRollup;
+    @Bind(property="content") private Rollup alertsRollup;
 
     public static void main(String[] args) {
         DesktopApplicationContext.main(Demo.class, args);

Modified: incubator/pivot/trunk/tutorials/src/pivot/tutorials/drawing/RotateLine.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tutorials/src/pivot/tutorials/drawing/RotateLine.java?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/tutorials/src/pivot/tutorials/drawing/RotateLine.java (original)
+++ incubator/pivot/trunk/tutorials/src/pivot/tutorials/drawing/RotateLine.java Wed May  6 21:24:48 2009
@@ -28,8 +28,8 @@
 import pivot.wtkx.Bindable;
 
 public class RotateLine extends Bindable implements Application {
-    @Load("rotate_line.wtkd") private Drawing drawing;
-    @Bind(resource="drawing") private Shape.Rotate rotation;
+    @Load(name="rotate_line.wtkd") private Drawing drawing;
+    @Bind(property="drawing") private Shape.Rotate rotation;
 
     private Window window = null;
 

Modified: incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/StockTracker.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/StockTracker.java?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/StockTracker.java (original)
+++ incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/StockTracker.java Wed May  6 21:24:48 2009
@@ -28,7 +28,6 @@
 import pivot.collections.List;
 import pivot.collections.Sequence;
 import pivot.serialization.CSVSerializer;
-import pivot.util.Resources;
 import pivot.util.concurrent.Task;
 import pivot.util.concurrent.TaskListener;
 import pivot.web.GetQuery;
@@ -52,23 +51,25 @@
 import pivot.wtk.TextInputTextListener;
 import pivot.wtk.Window;
 import pivot.wtk.text.TextNode;
-import pivot.wtkx.WTKXSerializer;
-
-public class StockTracker implements Application {
-    private Locale locale = null;
-    private Resources resources = null;
+import pivot.wtkx.Bindable;
 
+public class StockTracker extends Bindable implements Application {
     private ArrayList<String> symbols = new ArrayList<String>();
 
-    private Window window = null;
-    private TableView stocksTableView = null;
-    private TextInput symbolTextInput = null;
-    private Button addSymbolButton = null;
-    private Button removeSymbolsButton = null;
-    private Label lastUpdateLabel = null;
-    private Button yahooFinanceButton = null;
-    private Container detailRootPane = null;
-    private Label detailChangeLabel = null;
+    @Load(name="stocktracker.wtkx") private Window window;
+
+    @Bind(property="window") private TableView stocksTableView;
+    @Bind(property="window") private TextInput symbolTextInput;
+    @Bind(property="window") private Button addSymbolButton;
+    @Bind(property="window") private Button removeSymbolsButton;
+    @Bind(property="window") private Label lastUpdateLabel;
+    @Bind(property="window") private Button yahooFinanceButton;
+
+    @Bind(property="window", id="detail.rootPane")
+    private Container detailRootPane;
+
+    @Bind(property="window", id="detail.changeLabel")
+    private Label detailChangeLabel;
 
     private GetQuery getQuery = null;
 
@@ -98,16 +99,14 @@
         throws Exception {
         // Set the locale
         String language = properties.get(LANGUAGE_PROPERTY_NAME);
-        locale = (language == null) ? Locale.getDefault() : new Locale(language);
-        resources = new Resources(getClass().getName(), locale, "UTF8");
+        if (language != null) {
+            Locale.setDefault(new Locale(language));
+        }
 
-        // Load the application's UI
-        WTKXSerializer wtkxSerializer = new WTKXSerializer(resources);
-        Component content =
-            (Component)wtkxSerializer.readObject("pivot/tutorials/stocktracker/stocktracker.wtkx");
+        // Bind to the WTKX source
+        bind();
 
         // Wire up event handlers
-        stocksTableView = (TableView)wtkxSerializer.getObjectByName("stocksTableView");
         stocksTableView.getTableViewSelectionListeners().add(new TableViewSelectionListener() {
             public void selectedRangeAdded(TableView tableView, int rangeStart, int rangeEnd) {
                 // No-op
@@ -140,7 +139,6 @@
             }
         });
 
-        symbolTextInput = (TextInput)wtkxSerializer.getObjectByName("symbolTextInput");
         symbolTextInput.getTextInputTextListeners().add(new TextInputTextListener() {
             public void textChanged(TextInput textInput) {
                 TextNode textNode = textInput.getTextNode();
@@ -166,23 +164,18 @@
             }
         });
 
-        addSymbolButton = (Button)wtkxSerializer.getObjectByName("addSymbolButton");
         addSymbolButton.getButtonPressListeners().add(new ButtonPressListener() {
             public void buttonPressed(Button button) {
                 addSymbol();
             }
         });
 
-        removeSymbolsButton = (Button)wtkxSerializer.getObjectByName("removeSymbolsButton");
         removeSymbolsButton.getButtonPressListeners().add(new ButtonPressListener() {
             public void buttonPressed(Button button) {
                 removeSelectedSymbols();
             }
         });
 
-        lastUpdateLabel = (Label)wtkxSerializer.getObjectByName("lastUpdateLabel");
-
-        yahooFinanceButton = (Button)wtkxSerializer.getObjectByName("yahooFinanceButton");
         yahooFinanceButton.getButtonPressListeners().add(new ButtonPressListener() {
             public void buttonPressed(Button button) {
                 try {
@@ -192,14 +185,6 @@
             }
         });
 
-        detailRootPane = (Container)wtkxSerializer.getObjectByName("detail.rootPane");
-
-        detailChangeLabel = (Label)wtkxSerializer.getObjectByName("detail.changeLabel");
-
-        window = new Window();
-        window.setTitle((String)resources.get("stockTracker"));
-        window.setContent(content);
-        window.setMaximized(true);
         window.open(display);
 
         refreshTable();
@@ -280,10 +265,8 @@
                     }
 
                     DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,
-                        DateFormat.MEDIUM, locale);
-                    String lastUpdateText = resources.get("lastUpdate")
-                        + ": " + dateFormat.format(new Date());
-                    lastUpdateLabel.setText(lastUpdateText);
+                        DateFormat.MEDIUM, Locale.getDefault());
+                    lastUpdateLabel.setText(dateFormat.format(new Date()));
 
                     getQuery = null;
                 }

Modified: incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/stocktracker.wtkx
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/stocktracker.wtkx?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/stocktracker.wtkx (original)
+++ incubator/pivot/trunk/tutorials/src/pivot/tutorials/stocktracker/stocktracker.wtkx Wed May  6 21:24:48 2009
@@ -16,92 +16,98 @@
 limitations under the License.
 -->
 
-<TablePane styles="{padding:8, horizontalSpacing:6, verticalSpacing:6}"
+<Window title="%stockTracker" maximized="true"
     xmlns:wtkx="http://incubator.apache.org/pivot/wtkx/1.1"
     xmlns:content="pivot.wtk.content"
     xmlns:stocktracker="pivot.tutorials.stocktracker"
     xmlns="pivot.wtk">
-    <columns>
-        <TablePane.Column width="244" />
-        <TablePane.Column width="1*" />
-    </columns>
-
-    <rows>
-        <TablePane.Row height="-1">
-            <Label text="%stockTracker"
-                styles="{fontBold:true, fontSize:14, verticalAlignment:'center'}" />
-        </TablePane.Row>
-
-        <TablePane.Row height="1*">
-            <Border styles="{padding:0, color:10}">
-                <content>
-                    <ScrollPane horizontalScrollBarPolicy="fillToCapacity"
-                        verticalScrollBarPolicy="fillToCapacity">
-                        <view>
-                            <TableView wtkx:id="stocksTableView" selectMode="multi"
-                                styles="{showHorizontalGridLines:false}">
-                                <columns>
-                                    <TableView.Column name="symbol"
-                                        headerData="%symbol" width="80" />
-                                    <TableView.Column name="value" headerData="%value" width="80">
-                                        <cellRenderer>
-                                            <content:TableViewNumberCellRenderer styles="{horizontalAlignment:'right'}"
-                                                numberFormat="$$0.00"/>
-                                        </cellRenderer>
-                                    </TableView.Column>
-                                    <TableView.Column name="change" headerData="%change" width="80">
-                                        <cellRenderer>
-                                            <stocktracker:ChangeCellRenderer styles="{horizontalAlignment:'right'}"
-                                                numberFormat="+0.00;-0.00"/>
-                                        </cellRenderer>
-                                    </TableView.Column>
-                                </columns>
-                            </TableView>
-                        </view>
-
-                        <columnHeader>
-                            <TableViewHeader tableView="$stocksTableView" styles="{headersPressable:false}"/>
-                        </columnHeader>
-                    </ScrollPane>
-                </content>
-            </Border>
-
-            <Border styles="{padding:6, color:10}">
-                <content>
-                    <wtkx:include namespace="detail" src="stocktracker.detail.wtkx" />
-                </content>
-            </Border>
-        </TablePane.Row>
-
-        <TablePane.Row height="-1">
-            <FlowPane
-                styles="{horizontalAlignment:'left', verticalAlignment:'center'}">
-                <Label text="%symbol" styles="{fontBold:true}" />
-                <TextInput wtkx:id="symbolTextInput" textSize="10"
-                    maximumLength="8" />
-                <LinkButton wtkx:id="addSymbolButton" enabled="false"
-                    tooltipText="%addSymbol">
-                    <buttonData>
-                        <content:ButtonData icon="@add.png" />
-                    </buttonData>
-                </LinkButton>
-                <LinkButton wtkx:id="removeSymbolsButton" enabled="false"
-                    tooltipText="%removeSymbol">
-                    <buttonData>
-                        <content:ButtonData icon="@delete.png" />
-                    </buttonData>
-                </LinkButton>
-            </FlowPane>
-        </TablePane.Row>
-
-        <TablePane.Row height="-1">
-            <Label wtkx:id="lastUpdateLabel"
-                styles="{fontItalic:true, fontSize:10}" />
-            <FlowPane styles="{horizontalAlignment:'right'}">
-                <Label text="%dataProvidedBy" />
-                <LinkButton wtkx:id="yahooFinanceButton"
-                    buttonData="%yahooFinance" />
-            </FlowPane>
-        </TablePane.Row>
-    </rows>
-</TablePane>
+    <content>
+        <TablePane styles="{padding:8, horizontalSpacing:6, verticalSpacing:6}">
+            <columns>
+                <TablePane.Column width="244" />
+                <TablePane.Column width="1*" />
+            </columns>
+
+            <rows>
+                <TablePane.Row height="-1">
+                    <Label text="%stockTracker"
+                        styles="{fontBold:true, fontSize:14, verticalAlignment:'center'}" />
+                </TablePane.Row>
+
+                <TablePane.Row height="1*">
+                    <Border styles="{padding:0, color:10}">
+                        <content>
+                            <ScrollPane horizontalScrollBarPolicy="fillToCapacity"
+                                verticalScrollBarPolicy="fillToCapacity">
+                                <view>
+                                    <TableView wtkx:id="stocksTableView" selectMode="multi"
+                                        styles="{showHorizontalGridLines:false}">
+                                        <columns>
+                                            <TableView.Column name="symbol"
+                                                headerData="%symbol" width="80" />
+                                            <TableView.Column name="value" headerData="%value" width="80">
+                                                <cellRenderer>
+                                                    <content:TableViewNumberCellRenderer styles="{horizontalAlignment:'right'}"
+                                                        numberFormat="$$0.00"/>
+                                                </cellRenderer>
+                                            </TableView.Column>
+                                            <TableView.Column name="change" headerData="%change" width="80">
+                                                <cellRenderer>
+                                                    <stocktracker:ChangeCellRenderer styles="{horizontalAlignment:'right'}"
+                                                        numberFormat="+0.00;-0.00"/>
+                                                </cellRenderer>
+                                            </TableView.Column>
+                                        </columns>
+                                    </TableView>
+                                </view>
+
+                                <columnHeader>
+                                    <TableViewHeader tableView="$stocksTableView" styles="{headersPressable:false}"/>
+                                </columnHeader>
+                            </ScrollPane>
+                        </content>
+                    </Border>
+
+                    <Border styles="{padding:6, color:10}">
+                        <content>
+                            <wtkx:include namespace="detail" src="stocktracker.detail.wtkx" />
+                        </content>
+                    </Border>
+                </TablePane.Row>
+
+                <TablePane.Row height="-1">
+                    <FlowPane
+                        styles="{horizontalAlignment:'left', verticalAlignment:'center'}">
+                        <Label text="%symbol" styles="{fontBold:true}" />
+                        <TextInput wtkx:id="symbolTextInput" textSize="10"
+                            maximumLength="8" />
+                        <LinkButton wtkx:id="addSymbolButton" enabled="false"
+                            tooltipText="%addSymbol">
+                            <buttonData>
+                                <content:ButtonData icon="@add.png" />
+                            </buttonData>
+                        </LinkButton>
+                        <LinkButton wtkx:id="removeSymbolsButton" enabled="false"
+                            tooltipText="%removeSymbol">
+                            <buttonData>
+                                <content:ButtonData icon="@delete.png" />
+                            </buttonData>
+                        </LinkButton>
+                    </FlowPane>
+                </TablePane.Row>
+
+                <TablePane.Row height="-1">
+                    <FlowPane>
+	                    <Label text="%lastUpdate"/>
+	                    <Label wtkx:id="lastUpdateLabel"/>
+                    </FlowPane>
+                    <FlowPane styles="{horizontalAlignment:'right'}">
+                        <Label text="%dataProvidedBy" />
+                        <LinkButton wtkx:id="yahooFinanceButton"
+                            buttonData="%yahooFinance" />
+                    </FlowPane>
+                </TablePane.Row>
+            </rows>
+        </TablePane>
+    </content>
+</Window>

Modified: incubator/pivot/trunk/wtk/src/pivot/wtk/media/drawing/Group.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtk/media/drawing/Group.java?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtk/media/drawing/Group.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtk/media/drawing/Group.java Wed May  6 21:24:48 2009
@@ -16,11 +16,8 @@
  */
 package pivot.wtk.media.drawing;
 
-import java.awt.BasicStroke;
-import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.Paint;
-import java.awt.geom.Rectangle2D;
 import java.util.Iterator;
 import pivot.collections.ArrayList;
 import pivot.collections.Sequence;
@@ -91,10 +88,12 @@
         }
 
         // Draw a debug rectangle
+        /*
         graphics.setColor(Color.DARK_GRAY);
         graphics.setStroke(new BasicStroke(0));
         Bounds bounds = getBounds();
         graphics.draw(new Rectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height));
+        */
     }
 
     @Override

Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java Wed May  6 21:24:48 2009
@@ -111,13 +111,13 @@
 
                     if (DEBUG) {
                         processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
-                            String.format("Processing load(%s, %s#%s)", loadAnnotation.value(),
+                            String.format("Processing load(%s, %s#%s)", loadAnnotation.name(),
                             tree.name.toString(), loadFieldName));
                     }
 
                     // Load the WTKX resource
                     sourceCode.append("wtkxSerializer = new pivot.wtkx.WTKXSerializer();");
-                    sourceCode.append(String.format("java.net.URL location = getClass().getResource(\"%s\");", loadAnnotation.value()));
+                    sourceCode.append(String.format("java.net.URL location = getClass().getResource(\"%s\");", loadAnnotation.name()));
                     sourceCode.append("try {");
                     sourceCode.append("value = wtkxSerializer.readObject(location);");
                     sourceCode.append("} catch (Exception ex) {");
@@ -142,7 +142,7 @@
 
                             if (DEBUG) {
                                 processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
-                                    String.format("Processing bind(%s.%s, %s#%s)", bindAnnotation.resource(),
+                                    String.format("Processing bind(%s.%s, %s#%s)", bindAnnotation.property(),
                                     bindID, tree.name.toString(), bindFieldName));
                             }
 
@@ -224,8 +224,8 @@
                 BindScope bindScope = bindScopeStack.peek();
 
                 if (bindScope.loadGroups != null
-                    && bindScope.loadGroups.containsKey(bindAnnotation.resource())) {
-                    BindScope.LoadGroup loadGroup = bindScope.loadGroups.get(bindAnnotation.resource());
+                    && bindScope.loadGroups.containsKey(bindAnnotation.property())) {
+                    BindScope.LoadGroup loadGroup = bindScope.loadGroups.get(bindAnnotation.property());
 
                     if (loadGroup.bindFields == null) {
                         loadGroup.bindFields = new ArrayList<JCTree.JCVariableDecl>();
@@ -235,7 +235,7 @@
                     bindTally++;
                 } else {
                     processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
-                        "Resource not found: " + bindAnnotation.resource(), element);
+                        "Resource not found: " + bindAnnotation.property(), element);
                 }
             }
         }

Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java?rev=772431&r1=772430&r2=772431&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java Wed May  6 21:24:48 2009
@@ -22,10 +22,15 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.net.URL;
+import java.util.Locale;
+import java.util.MissingResourceException;
 
+import pivot.collections.ArrayList;
 import pivot.collections.HashMap;
 import pivot.serialization.SerializationException;
+import pivot.util.Resources;
 
 /**
  * Base class for objects that wish to leverage WTKX binding annotations.
@@ -41,7 +46,9 @@
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
     protected static @interface Load {
-        public String value();
+        public String name();
+        public String resources() default "\0";
+        public String locale() default "\0";
     }
 
     /**
@@ -52,7 +59,7 @@
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
     protected static @interface Bind {
-        public String resource();
+        public String property();
         public String id() default "\0";
     }
 
@@ -60,88 +67,137 @@
      * Applies WTKX binding annotations to this bindable object.
      */
     protected void bind() throws IOException, BindException {
-        // Maps resource field name to the serializer that loaded the resource
-        HashMap<String, WTKXSerializer> wtkxSerializers = new HashMap<String, WTKXSerializer>();
-
-        // Walk field lists and resolve WTKX annotations
+        // Walk fields and resolve annotations
+        ArrayList<Class<?>> typeHierarchy = new ArrayList<Class<?>>();
         Class<?> type = getClass();
-        Field[] fields = type.getDeclaredFields();
-        for (int i = 0; i < fields.length; i++) {
-            Field field = fields[i];
-            Load loadAnnotation = field.getAnnotation(Load.class);
+        while (type != Bindable.class) {
+            typeHierarchy.add(type);
+            type = type.getSuperclass();
+        }
+
+        for (int i = typeHierarchy.getLength() - 1; i >= 0; i--) {
+            // Maps resource field name to the serializer that loaded the
+            // resource; we create it here so each subclass gets its own scope
+            HashMap<String, WTKXSerializer> wtkxSerializers = new HashMap<String, WTKXSerializer>();
 
-            if (loadAnnotation != null) {
-                // Create a serializer for the resource
+            type = typeHierarchy.get(i);
+            Field[] fields = type.getDeclaredFields();
+
+            for (int j = 0, n = fields.length; j < n; j++) {
+                Field field = fields[j];
                 String fieldName = field.getName();
-                assert(!wtkxSerializers.containsKey(fieldName));
+                int fieldModifiers = field.getModifiers();
 
-                WTKXSerializer wtkxSerializer = new WTKXSerializer();
-                wtkxSerializers.put(fieldName, wtkxSerializer);
+                Load loadAnnotation = field.getAnnotation(Load.class);
+                if (loadAnnotation != null) {
+                    // Ensure that we can write to the field
+                    if ((fieldModifiers & Modifier.FINAL) > 0) {
+                        throw new BindException(fieldName + " is final.");
+                    }
 
-                // Load the resource
-                URL location = type.getResource(loadAnnotation.value());
-                Object resource;
-                try {
-                    resource = wtkxSerializer.readObject(location);
-                } catch (SerializationException exception) {
-                    throw new BindException(exception);
-                }
+                    if ((fieldModifiers & Modifier.PUBLIC) == 0) {
+                        try {
+                            field.setAccessible(true);
+                        } catch(SecurityException exception) {
+                            throw new BindException(fieldName + " is not accessible.");
+                        }
+                    }
+
+                    assert(!wtkxSerializers.containsKey(fieldName));
 
-                // Set the resource into the field
-                if (!field.isAccessible()) {
+                    // Get the name of the resource file to use
+                    Resources resources = null;
+                    boolean defaultResources = false;
+
+                    String baseName = loadAnnotation.resources();
+                    if (baseName.equals("\0")) {
+                        baseName = type.getName();
+                        defaultResources = true;
+                    }
+
+                    // Get the resource locale
+                    Locale locale;
+                    String language = loadAnnotation.locale();
+                    if (language.equals("\0")) {
+                        locale = Locale.getDefault();
+                    } else {
+                        locale = new Locale(language);
+                    }
+
+                    // Attmpt to load the resources
                     try {
-                        field.setAccessible(true);
-                    } catch (Exception ex) {
-                        // No-op; the callers might have used public fields, in
-                        // which case we don't need to make them accessible
+                        resources = new Resources(baseName, locale, "UTF8");
+                    } catch(SerializationException exception) {
+                        throw new BindException(exception);
+                    } catch(MissingResourceException exception) {
+                        if (!defaultResources) {
+                            throw new BindException(baseName + " not found.");
+                        }
                     }
-                }
 
-                try {
-                    field.set(this, resource);
-                } catch (IllegalAccessException exception) {
-                    throw new BindException(exception);
-                }
-            }
+                    // Deserialize the value
+                    WTKXSerializer wtkxSerializer = new WTKXSerializer(resources);
+                    wtkxSerializers.put(fieldName, wtkxSerializer);
 
-            Bind bindAnnotation = field.getAnnotation(Bind.class);
-            if (bindAnnotation != null) {
-                if (loadAnnotation != null) {
-                    throw new BindException("Cannot combine " + Load.class.getName()
-                        + " and " + Bind.class.getName() + " annotations.");
-                }
+                    URL location = type.getResource(loadAnnotation.name());
+                    Object resource;
+                    try {
+                        resource = wtkxSerializer.readObject(location);
+                    } catch (SerializationException exception) {
+                        throw new BindException(exception);
+                    }
 
-                // Bind to the value loaded by the field's serializer
-                String fieldName = bindAnnotation.resource();
-                WTKXSerializer wtkxSerializer = wtkxSerializers.get(fieldName);
-                if (wtkxSerializer == null) {
-                    throw new BindException("\"" + fieldName + "\" is not a valid resource name.");
+                    // Set the deserialized value into the field
+                    try {
+                        field.set(this, resource);
+                    } catch (IllegalAccessException exception) {
+                        throw new BindException(exception);
+                    }
                 }
 
-                String id = bindAnnotation.id();
-                if ("\0".equals(id)) {
-                    id = field.getName();
-                }
+                Bind bindAnnotation = field.getAnnotation(Bind.class);
+                if (bindAnnotation != null) {
+                    if (loadAnnotation != null) {
+                        throw new BindException("Cannot combine " + Load.class.getName()
+                            + " and " + Bind.class.getName() + " annotations.");
+                    }
 
-                Object value = wtkxSerializer.getObjectByName(id);
-                if (value == null) {
-                    throw new BindException("\"" + id + "\" does not exist.");
-                }
+                    // Ensure that we can write to the field
+                    if ((fieldModifiers & Modifier.FINAL) > 0) {
+                        throw new BindException(fieldName + " is final.");
+                    }
 
-                // Set the value into the field
-                if (!field.isAccessible()) {
-                    try {
-                        field.setAccessible(true);
-                    } catch (Exception ex) {
-                        // No-op; the callers might have used public fields, in
-                        // which case we don't need to make them accessible
+                    if ((fieldModifiers & Modifier.PUBLIC) == 0) {
+                        try {
+                            field.setAccessible(true);
+                        } catch(SecurityException exception) {
+                            throw new BindException(fieldName + " is not accessible.");
+                        }
+                    }
+
+                    // Bind to the value loaded by the property's serializer
+                    String property = bindAnnotation.property();
+                    WTKXSerializer wtkxSerializer = wtkxSerializers.get(property);
+                    if (wtkxSerializer == null) {
+                        throw new BindException("Property \"" + property + "\" has not been loaded.");
+                    }
+
+                    String id = bindAnnotation.id();
+                    if (id.equals("\0")) {
+                        id = field.getName();
                     }
-                }
 
-                try {
-                    field.set(this, value);
-                } catch (IllegalAccessException exception) {
-                    throw new BindException(exception);
+                    Object value = wtkxSerializer.getObjectByName(id);
+                    if (value == null) {
+                        throw new BindException("\"" + id + "\" does not exist.");
+                    }
+
+                    // Set the value into the field
+                    try {
+                        field.set(this, value);
+                    } catch (IllegalAccessException exception) {
+                        throw new BindException(exception);
+                    }
                 }
             }
         }