diff --git a/examples/user_types/Decoder.java b/examples/user_types/Decoder.java
index cbfcb24a41425e42125d82949467ca645516077e..929e92e3a155617312db09d3e414cf67f2cf8ec4 100644
--- a/examples/user_types/Decoder.java
+++ b/examples/user_types/Decoder.java
@@ -4,19 +4,21 @@ import java.io.InputStream;
 
 import se.lth.control.labcomm.DecoderChannel;
 import se.lth.control.labcomm.TypeDef;
-import se.lth.control.labcomm.TypeBinding;
+import se.lth.control.labcomm.TypeDefParser;
+//import se.lth.control.labcomm.TypeBinding;
 
 public class Decoder
   implements twoLines.Handler,
+//             TypeDef.Handler,
+//             TypeBinding.Handler,
+             TypeDefParser.TypeDefListener,
              twoInts.Handler,
              theFirstInt.Handler,
-             theSecondInt.Handler,
-             TypeDef.Handler,
-             TypeBinding.Handler
-
+             theSecondInt.Handler
 {
 
-  DecoderChannel decoder;
+  private DecoderChannel decoder;
+  private TypeDefParser tdp;
 
   public Decoder(InputStream in) 
     throws Exception 
@@ -26,9 +28,13 @@ public class Decoder
     twoLines.register(decoder, this);
     theFirstInt.register(decoder, this);
     theSecondInt.register(decoder, this);
-    TypeDef.register(decoder, this);
-    TypeBinding.register(decoder, this);
+    this.tdp = TypeDefParser.registerTypeDefParser(decoder); 
+ //   TypeDef.register(decoder, this);
+ //   TypeBinding.register(decoder, this);
 
+        
+    tdp.addListener(this);
+    
     try {
       System.out.println("Running decoder.");
       decoder.run();
@@ -45,12 +51,16 @@ public class Decoder
     return "Line from "+genPoint(l.start)+" to "+genPoint(l.end);
   }
 
-  public void handle_TypeDef(TypeDef d) throws java.io.IOException {
-    System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")");
-  }
+//  public void handle_TypeDef(TypeDef d) throws java.io.IOException {
+//    System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")");
+//  }
+//
+//  public void handle_TypeBinding(TypeBinding d) throws java.io.IOException {
+//    System.out.println("Got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+"");
+//  }
 
-  public void handle_TypeBinding(TypeBinding d) throws java.io.IOException {
-    System.out.println("Got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+"");
+  public void onTypeDef(TypeDef d) {
+    System.out.println("onTypeDef: "+d.getName()+"("+d.getIndex()+")");
   }
 
   public void handle_twoInts(twoInts d) throws java.io.IOException {
diff --git a/lib/java/Makefile b/lib/java/Makefile
index bd3055c0a6ffe61f955e96fbfb2a67d79e730b54..697fd803d86bac15614e285084eab70703e8dca3 100644
--- a/lib/java/Makefile
+++ b/lib/java/Makefile
@@ -12,6 +12,7 @@ MODULES=Constant \
 	SampleType \
 	TypeDef \
 	TypeBinding \
+	TypeDefParser \
 	Writer \
 	WriterWrapper
 
diff --git a/lib/java/se/lth/control/labcomm/TypeBinding.java b/lib/java/se/lth/control/labcomm/TypeBinding.java
index 36b84fb02ccf321290e567cea7c6a7b49df75340..0ea2782e154481457418a07840e51b4adad08bee 100644
--- a/lib/java/se/lth/control/labcomm/TypeBinding.java
+++ b/lib/java/se/lth/control/labcomm/TypeBinding.java
@@ -28,74 +28,92 @@ public class TypeBinding implements SampleType {
   public interface Handler extends SampleHandler {
     public void handle_TypeBinding(TypeBinding value) throws Exception;
   }
-  
+
   public static void register(Decoder d, Handler h) throws IOException {
     d.register(Dispatcher.singleton(), h);
   }
-  
+
   public static void register(Encoder e) throws IOException {
     register(e,false);
   }
-  
+
   public static void register(Encoder e, boolean sendMetaData) throws IOException {
     throw new IOException("cannot send TypeDefs");
   }
-  
+
  static class Dispatcher implements SampleDispatcher<TypeBinding> {
-    
+
     private static Dispatcher singleton;
-    
+
     public synchronized static Dispatcher singleton() {
       if(singleton==null) singleton=new Dispatcher();
       return singleton;
     }
-    
+
     public Class<TypeBinding> getSampleClass() {
       return TypeBinding.class;
     }
-    
+
     public String getName() {
       return "TypeBinding";
     }
-    
+
     public byte getTypeDeclTag() {
       throw new Error("Should not be called");
     }
-    
+
     public boolean isSample() {
       throw new Error("Should not be called");
     }
     public boolean hasStaticSignature() {
       throw new Error("Should not be called");
     }
-    
+
     /** return the flat signature. Intended use is on decoder side */
     public byte[] getSignature() {
       return null; // not used for matching
     }
-    
+
     public void encodeTypeDef(Encoder e, int index) throws IOException{
       throw new Error("Should not be called");
     }
-    
+
 //    public boolean canDecodeAndHandle() {
 //      return true;
 //    }
-    
+
     public void decodeAndHandle(Decoder d,
                                 SampleHandler h) throws Exception {
       ((Handler)h).handle_TypeBinding(TypeBinding.decode(d));
     }
-    
+
     public boolean hasDependencies() {
         return false;
     }
   }
-  
+
   public static void encode(Encoder e, TypeBinding value) throws IOException {
     throw new Error("Should not be called");
   }
-  
+
+  /* HERE BE DRAGONS!
+   * This exposes (and relies on the stability of) indices that are
+   * internal to a decoder.
+   *
+   * The SAMPLE_DEF and TYPE_DEF must already have been received for the
+   * indices to be known, so this can be changed to instead return
+   * references to the SampleDispactcher corresponding to the sample type
+   * and the matching TypeDef.
+   *
+   * Sketch:
+   *
+   * SampleDispatcher sd = d.getDispatcherForId(sampleIndex);
+   * TypeDef td = d.getTypeDefForId(typeIndex);
+   *
+   * return new TypeBinding(sd, td);
+   *
+   * assuming that the Decoder keeps a registry for TypeDefs
+   */
   public static TypeBinding decode(Decoder d) throws IOException {
     TypeBinding result;
     int sampleIndex = d.decodePacked32();
diff --git a/lib/java/se/lth/control/labcomm/TypeDef.java b/lib/java/se/lth/control/labcomm/TypeDef.java
index 8c9cc7063d4b0614d229dc023a9fc3064128ab98..c7a78be4710cd17c021324e5593ec0de56dc32c4 100644
--- a/lib/java/se/lth/control/labcomm/TypeDef.java
+++ b/lib/java/se/lth/control/labcomm/TypeDef.java
@@ -21,6 +21,10 @@ public class TypeDef implements SampleType {
     return name;
   }
 
+  public byte[] getSignature() {
+    return signature;
+  }
+
   public void dump() {
       System.out.print("=== TypeDef "+getName()+"( "+Integer.toHexString(getIndex())+") : ");
       for (byte b : signature) {
@@ -99,6 +103,9 @@ public class TypeDef implements SampleType {
     throw new Error("Should not be called");
   }
   
+  protected TypeDef() {
+  }
+
   public TypeDef(int index, String name, byte sig[]) {
       this.index = index;
       this.name = name;
diff --git a/lib/java/se/lth/control/labcomm/TypeDefParser.java b/lib/java/se/lth/control/labcomm/TypeDefParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a7f7aa7410fa9ba36a4de5318305b79d8ea20f8
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm/TypeDefParser.java
@@ -0,0 +1,77 @@
+package se.lth.control.labcomm;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import se.lth.control.labcomm.Decoder;
+import se.lth.control.labcomm.TypeDef;
+import se.lth.control.labcomm.TypeBinding;
+
+public class TypeDefParser implements TypeDef.Handler, TypeBinding.Handler {
+
+    static class SelfBinding extends TypeDef {
+
+        private byte[] dummy = new byte[0];
+        public String getName() {return "self";} 
+        public int getIndex() {return 0;}
+        public byte[] getSignature() {return dummy;}
+    }
+
+    public interface TypeDefListener {
+        void onTypeDef(TypeDef d);
+    }
+
+    private HashMap<Integer,TypeDef> typeDefs;
+    private HashMap<Integer,Integer> typeBindings;
+    private HashSet<TypeDefListener> listeners;
+
+    protected TypeDefParser() {
+        typeDefs = new HashMap<Integer,TypeDef>();
+        typeBindings = new HashMap<Integer,Integer>();
+        listeners = new HashSet<TypeDefListener>();
+
+        typeDefs.put(0, new SelfBinding());
+    }
+
+    public void addListener(TypeDefListener l) {
+        listeners.add(l);
+    }
+
+    public void handle_TypeDef(TypeDef d) throws java.io.IOException {
+        //System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")");
+        typeDefs.put(d.getIndex(), d);
+    }
+
+    public void handle_TypeBinding(TypeBinding d) throws java.io.IOException {
+        //System.out.println("TDP got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+"");
+        typeBindings.put(d.getSampleIndex(), d.getTypeIndex());
+        
+        Iterator<TypeDefListener> it = listeners.iterator();
+        while(it.hasNext()){
+            //it.next().onTypeDef(getTypeDefForIndex(d.getSampleIndex()));
+            it.next().onTypeDef(typeDefs.get(d.getTypeIndex()));
+        }
+    }
+
+    //* temporary testing method */
+    public TypeDef getTypeDefForIndex(int sampleIndex) {
+        return typeDefs.get(typeBindings.get(sampleIndex));
+    }
+
+
+    /** Factory method
+     *  @return a new TypeDefParser registered on d
+     */
+    public static TypeDefParser registerTypeDefParser(Decoder d) throws java.io.IOException  {
+
+        TypeDefParser res = new TypeDefParser();
+
+        TypeDef.register(d,res);
+        TypeBinding.register(d,res);
+
+        return res;
+    }
+}
+
+