]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/ClassBindingFactory.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / ClassBindingFactory.java
index 94d3ed5f6d4f323950cfec22df2095193d9e8a13..8d29ad70c24ac4c8896293b22ac82817b1c617f3 100644 (file)
-package org.simantics.databoard.binding.reflection;\r
-\r
-import java.lang.annotation.Annotation;\r
-import java.lang.reflect.Array;\r
-import java.lang.reflect.Constructor;\r
-import java.lang.reflect.Field;\r
-import java.lang.reflect.GenericArrayType;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.lang.reflect.Modifier;\r
-import java.lang.reflect.ParameterizedType;\r
-import java.lang.reflect.Type;\r
-import java.lang.reflect.TypeVariable;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.concurrent.CopyOnWriteArrayList;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.annotations.ArgumentImpl;\r
-import org.simantics.databoard.annotations.Arguments;\r
-import org.simantics.databoard.annotations.Identifier;\r
-import org.simantics.databoard.annotations.Length;\r
-import org.simantics.databoard.annotations.MIMEType;\r
-import org.simantics.databoard.annotations.Name;\r
-import org.simantics.databoard.annotations.Optional;\r
-import org.simantics.databoard.annotations.Pattern;\r
-import org.simantics.databoard.annotations.Range;\r
-import org.simantics.databoard.annotations.Referable;\r
-import org.simantics.databoard.annotations.Union;\r
-import org.simantics.databoard.annotations.Unit;\r
-import org.simantics.databoard.binding.ArrayBinding;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.MapBinding;\r
-import org.simantics.databoard.binding.OptionalBinding;\r
-import org.simantics.databoard.binding.RecordBinding;\r
-import org.simantics.databoard.binding.error.BindingConstructionException;\r
-import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;\r
-import org.simantics.databoard.binding.factory.BindingRepository;\r
-import org.simantics.databoard.binding.factory.DefaultBindingFactory;\r
-import org.simantics.databoard.binding.factory.TypeBindingFactory;\r
-import org.simantics.databoard.binding.impl.ByteBindingDefault;\r
-import org.simantics.databoard.binding.impl.DoubleBindingDefault;\r
-import org.simantics.databoard.binding.impl.FloatBindingDefault;\r
-import org.simantics.databoard.binding.impl.IntegerBindingDefault;\r
-import org.simantics.databoard.binding.impl.LongBindingDefault;\r
-import org.simantics.databoard.binding.impl.OptionalBindingDefault;\r
-import org.simantics.databoard.binding.impl.StringBindingDefault;\r
-import org.simantics.databoard.binding.impl.UnsignedByteBinding;\r
-import org.simantics.databoard.binding.impl.UnsignedIntegerBinding;\r
-import org.simantics.databoard.binding.impl.UnsignedLongBinding;\r
-import org.simantics.databoard.binding.mutable.MutableByteBinding;\r
-import org.simantics.databoard.binding.mutable.MutableDoubleBinding;\r
-import org.simantics.databoard.binding.mutable.MutableFloatBinding;\r
-import org.simantics.databoard.binding.mutable.MutableIntegerBinding;\r
-import org.simantics.databoard.binding.mutable.MutableLongBinding;\r
-import org.simantics.databoard.binding.mutable.MutableStringBinding;\r
-import org.simantics.databoard.primitives.MutableBoolean;\r
-import org.simantics.databoard.primitives.MutableByte;\r
-import org.simantics.databoard.primitives.MutableDouble;\r
-import org.simantics.databoard.primitives.MutableFloat;\r
-import org.simantics.databoard.primitives.MutableInteger;\r
-import org.simantics.databoard.primitives.MutableLong;\r
-import org.simantics.databoard.primitives.MutableString;\r
-import org.simantics.databoard.primitives.UnsignedByte;\r
-import org.simantics.databoard.primitives.UnsignedInteger;\r
-import org.simantics.databoard.primitives.UnsignedLong;\r
-import org.simantics.databoard.type.ArrayType;\r
-import org.simantics.databoard.type.ByteType;\r
-import org.simantics.databoard.type.Component;\r
-import org.simantics.databoard.type.DoubleType;\r
-import org.simantics.databoard.type.FloatType;\r
-import org.simantics.databoard.type.IntegerType;\r
-import org.simantics.databoard.type.LongType;\r
-import org.simantics.databoard.type.MapType;\r
-import org.simantics.databoard.type.OptionalType;\r
-import org.simantics.databoard.type.RecordType;\r
-import org.simantics.databoard.type.StringType;\r
-import org.simantics.databoard.type.UnionType;\r
-import org.simantics.databoard.util.ArrayUtils;\r
-import org.simantics.databoard.util.IdentityHashSet;\r
-import org.simantics.databoard.util.RangeException;\r
-\r
-/**\r
- * Type Factory constructs data types from reflection requests.\r
- * Successfully constructed types are placed in the repository that was given \r
- * at construction time.\r
- *  \r
- * @author Toni Kalajainen\r
- */\r
-public class ClassBindingFactory {\r
-       \r
-       /**\r
-        * Map of failed constructions. \r
-        */\r
-       Map<BindingRequest, BindingConstructionException> failures = new HashMap<BindingRequest, BindingConstructionException>();\r
-       \r
-       /**\r
-        * Map that contains in incomplete constructions.\r
-        */\r
-       Map<BindingRequest, Binding> inprogress = new HashMap<BindingRequest, Binding>();\r
-       \r
-       /**\r
-        * Repository where successful constructions are placed. \r
-        */\r
-       BindingRepository repository;   \r
-       \r
-       List<BindingProvider> subFactories = new CopyOnWriteArrayList<BindingProvider>();\r
-\r
-       /** Asm based binding factory for Classes, this is used if Asm library is available, else null */\r
-       RecordBindingProvider asmClassBindingFactory;\r
-       \r
-       /** Reflection based binding factory for Classes, this has poorer performance than asm factory */\r
-       RecordBindingProvider refClassBindingFactory;\r
-\r
-       /** Factory for creating default bindings for data types. */\r
-       TypeBindingFactory defaultBindingFactory;\r
-       \r
-       /**\r
-        * Construct a new reflection binding factory \r
-        */\r
-       public ClassBindingFactory() {\r
-               init();\r
-               this.repository = new BindingRepository();\r
-               this.defaultBindingFactory = new DefaultBindingFactory();\r
-       }\r
-       \r
-       /**\r
-        * Construct a new reflection binding factory that places constructed \r
-        * bindings into user given repository.\r
-        * \r
-        * @param repository\r
-        */\r
-       public ClassBindingFactory(BindingRepository repository, TypeBindingFactory defaultBindingFactory) {\r
-               init();\r
-               this.repository = repository;\r
-               this.defaultBindingFactory = defaultBindingFactory;\r
-       }\r
-       \r
-       void init() {\r
-               refClassBindingFactory = new ReflectionBindingProvider();\r
-               try {\r
-                       // Check ASM Exists\r
-                       Class.forName("org.objectweb.asm.ClassWriter");\r
-                       // Create factory\r
-                       Class<?> y = Class.forName("org.simantics.databoard.binding.reflection.AsmBindingProvider");\r
-                       Constructor<?> c = y.getConstructor();\r
-                       asmClassBindingFactory = (RecordBindingProvider) c.newInstance();\r
-                       return;\r
-               } catch (ClassNotFoundException e) {\r
-               } catch (InstantiationException e) {\r
-               } catch (IllegalAccessException e) {\r
-               } catch (IllegalArgumentException e) {\r
-               } catch (InvocationTargetException e) {\r
-               } catch (SecurityException e) {\r
-               } catch (NoSuchMethodException e) {\r
-               }\r
-       }\r
-       \r
-       public void addFactory(BindingProvider factory) \r
-       {\r
-               if (!subFactories.contains(factory)) {\r
-                       this.subFactories.add(factory);\r
-               }\r
-       }\r
-       \r
-       public void removeFactory(BindingProvider factory) {\r
-               subFactories.remove(factory);\r
-       }\r
-       \r
-       public BindingRepository getRepository() {\r
-               return repository;\r
-       }\r
-       \r
-       /**\r
-        * Constructs a binding to comply to class request.\r
-        * This is the method sub-classes implement. \r
-        * The implementation should use the inprogress -map for construction of \r
-        * bindings that have component types.\r
-        * \r
-        *  e.g. \r
-        *   inprogress.put(request, notCompletelyConstructedBinding);\r
-        *   Binding componentBinding = construct( componentRequest );\r
-        *   notCompletelyConstructedBinding.setChild( componentBinding );\r
-        *   inprogress.remove(request);\r
-        *   \r
-        * try-finally is not needed.\r
-        * \r
-        * @param request\r
-        * @return\r
-        * @throws BindingConstructionException\r
-        * @throws RangeException\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-    protected Binding doConstruct(BindingRequest request) throws BindingConstructionException, RangeException\r
-       {\r
-               // Optional\r
-       if(request.hasAnnotation(Optional.class))\r
-       {               \r
-               Optional optional = request.getAnnotation(Optional.class); \r
-               Annotation[] newAnnotations = ArrayUtils.dropElements(request.annotations, optional);\r
-               BindingRequest componentRequest = new BindingRequest(request.getClazz(), newAnnotations);\r
-               OptionalType type = new OptionalType();\r
-               OptionalBinding binding = new OptionalBindingDefault(type, null);\r
-                       inprogress.put(request, binding);\r
-                       binding.componentBinding = construct( componentRequest );\r
-                       type.componentType = binding.componentBinding.type();\r
-                       inprogress.remove(request);\r
-                       \r
-                       return binding;\r
-       }\r
-\r
-            \r
-       \r
-       // Primitive\r
-               {               \r
-                       Range range = request.getAnnotation(Range.class);\r
-                       Unit unit = request.getAnnotation(Unit.class);\r
-                       \r
-                       if (request.getClazz() == Integer.class || request.getClazz() == int.class || request.getClazz() == MutableInteger.class || UnsignedInteger.class.isAssignableFrom(request.getClazz())) {\r
-                               Binding binding = null; \r
-                               if (range==null && unit==null) {\r
-                                       if (request.getClazz() == int.class) binding = Bindings.INTEGER;\r
-                                       if (request.getClazz() == Integer.class) binding = Bindings.INTEGER;\r
-                                       if (request.getClazz() == MutableInteger.class) binding = Bindings.MUTABLE_INTEGER;\r
-                                       if (request.getClazz() == UnsignedInteger.Mutable.class) binding = Bindings.MUTABLE_UNSIGNED_INTEGER;\r
-                                       if (request.getClazz() == UnsignedInteger.Immutable.class) binding = Bindings.UNSIGNED_INTEGER;\r
-                               } else {\r
-                                       IntegerType type = new IntegerType();\r
-                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );\r
-                                       type.setUnit( unit==null ? null : unit.value() );\r
-\r
-                                       if (request.getClazz() == int.class) binding = new IntegerBindingDefault(type);\r
-                                       if (request.getClazz() == Integer.class) binding = new IntegerBindingDefault(type);\r
-                                       if (request.getClazz() == MutableInteger.class) binding = new MutableIntegerBinding(type);\r
-                                       if (request.getClazz() == UnsignedInteger.Mutable.class) binding = new UnsignedIntegerBinding.Mutable(type);\r
-                                       if (request.getClazz() == UnsignedInteger.Immutable.class) binding = new UnsignedIntegerBinding.Immutable(type);\r
-                               }\r
-                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());\r
-                               \r
-                               repository.put(request, binding);\r
-                               return binding;\r
-                       }\r
-                               \r
-                       if (request.getClazz() == Byte.class || request.getClazz() == byte.class || request.getClazz() == MutableByte.class || UnsignedByte.class.isAssignableFrom(request.getClazz())) {\r
-                               Binding binding = null; \r
-                               if (range==null && unit==null) {\r
-                                       if (request.getClazz() == byte.class) binding = Bindings.BYTE;\r
-                                       if (request.getClazz() == Byte.class) binding = Bindings.BYTE;\r
-                                       if (request.getClazz() == MutableByte.class) binding = Bindings.MUTABLE_BYTE;\r
-                                       if (request.getClazz() == UnsignedByte.Mutable.class) binding = Bindings.MUTABLE_UNSIGNED_BYTE;\r
-                                       if (request.getClazz() == UnsignedByte.Immutable.class) binding = Bindings.UNSIGNED_BYTE;\r
-                               } else {\r
-                                       ByteType type = new ByteType();\r
-                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );\r
-                                       type.setUnit( unit==null ? null : unit.value() );\r
-\r
-                                       if (request.getClazz() == byte.class) binding = new ByteBindingDefault(type);\r
-                                       if (request.getClazz() == Byte.class) binding = new ByteBindingDefault(type);\r
-                                       if (request.getClazz() == MutableByte.class) binding = new MutableByteBinding(type);\r
-                                       if (request.getClazz() == UnsignedByte.Mutable.class) binding = new UnsignedByteBinding.Mutable(type);\r
-                                       if (request.getClazz() == UnsignedByte.Immutable.class) binding = new UnsignedByteBinding.Immutable(type);\r
-                               }\r
-                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());\r
-                               \r
-                               repository.put(request, binding);                       \r
-                               return binding;\r
-                       }                       \r
-                       \r
-                       if (request.getClazz() == Long.class || request.getClazz() == long.class || request.getClazz() == MutableLong.class || UnsignedLong.class.isAssignableFrom(request.getClazz())) {\r
-                               Binding binding = null; \r
-                               if (range==null && unit==null) {\r
-                                       if (request.getClazz() == long.class) binding = Bindings.LONG;\r
-                                       if (request.getClazz() == Long.class) binding = Bindings.LONG;\r
-                                       if (request.getClazz() == MutableLong.class) binding = Bindings.MUTABLE_LONG;\r
-                                       if (request.getClazz() == UnsignedLong.Mutable.class) binding = Bindings.MUTABLE_UNSIGNED_LONG;\r
-                                       if (request.getClazz() == UnsignedLong.Immutable.class) binding = Bindings.UNSIGNED_LONG;\r
-                               } else {\r
-                                       LongType type = new LongType();\r
-                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );\r
-                                       type.setUnit( unit==null ? null : unit.value() );\r
-\r
-                                       if (request.getClazz() == long.class) binding = new LongBindingDefault(type);\r
-                                       if (request.getClazz() == Long.class) binding = new LongBindingDefault(type);\r
-                                       if (request.getClazz() == MutableLong.class) binding = new MutableLongBinding(type);\r
-                                       if (request.getClazz() == UnsignedLong.Mutable.class) binding = new UnsignedLongBinding.Mutable(type);\r
-                                       if (request.getClazz() == UnsignedLong.Immutable.class) binding = new UnsignedLongBinding.Immutable(type);\r
-                               }\r
-                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());\r
-                               \r
-                               repository.put(request, binding);                       \r
-                               return binding;\r
-                       }\r
-                       \r
-                       if (request.getClazz() == Float.class || request.getClazz() == float.class || request.getClazz() == MutableFloat.class) {\r
-                               Binding binding = null; \r
-                               if (range==null && unit==null) {\r
-                                       if (request.getClazz() == float.class) binding = Bindings.FLOAT;\r
-                                       if (request.getClazz() == Float.class) binding = Bindings.FLOAT;\r
-                                       if (request.getClazz() == MutableFloat.class) binding = Bindings.MUTABLE_FLOAT;\r
-                               } else {\r
-                                       FloatType type = new FloatType();\r
-                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );\r
-                                       type.setUnit( unit==null ? null : unit.value() );\r
-\r
-                                       if (request.getClazz() == float.class) binding = new FloatBindingDefault(type);\r
-                                       if (request.getClazz() == Float.class) binding = new FloatBindingDefault(type);\r
-                                       if (request.getClazz() == MutableFloat.class) binding = new MutableFloatBinding(type);\r
-                               }\r
-                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());\r
-                               \r
-                               repository.put(request, binding);                       \r
-                               return binding;\r
-                       }\r
-                       \r
-                       if (request.getClazz() == Double.class || request.getClazz() == double.class || request.getClazz() == MutableDouble.class) {\r
-                               Binding binding = null; \r
-                               if (range==null && unit==null) {\r
-                                       if (request.getClazz() == double.class) binding = Bindings.DOUBLE;\r
-                                       if (request.getClazz() == Double.class) binding = Bindings.DOUBLE;\r
-                                       if (request.getClazz() == MutableDouble.class) binding = Bindings.MUTABLE_DOUBLE;\r
-                               } else {\r
-                                       DoubleType type = new DoubleType();\r
-                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );\r
-                                       type.setUnit( unit==null ? null : unit.value() );\r
-\r
-                                       if (request.getClazz() == double.class) binding = new DoubleBindingDefault(type);\r
-                                       if (request.getClazz() == Double.class) binding = new DoubleBindingDefault(type);\r
-                                       if (request.getClazz() == MutableDouble.class) binding = new MutableDoubleBinding(type);\r
-                               }\r
-                               \r
-                               repository.put(request, binding);                       \r
-                               return binding;\r
-                       }\r
-\r
-                       if (request.getClazz() == Boolean.class || request.getClazz() == boolean.class || request.getClazz() == MutableBoolean.class) {\r
-                               Binding binding = null;\r
-                       if (request.getClazz() == Boolean.class || request.getClazz() == boolean.class) binding = Bindings.BOOLEAN;\r
-                       if (request.getClazz() == MutableBoolean.class) binding = Bindings.MUTABLE_BOOLEAN;             \r
-                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());\r
-                               \r
-                               repository.put(request, binding);                       \r
-                               return binding;\r
-                       }\r
-\r
-                       if (request.getClazz() == String.class || request.getClazz() == MutableString.class) {\r
-                               Length length = request.getAnnotation(Length.class);\r
-                               MIMEType mimeType = request.getAnnotation(MIMEType.class);\r
-                               Pattern pattern = request.getAnnotation(Pattern.class);\r
-                               Binding binding = null;\r
-                               if (length==null && mimeType==null && pattern==null) {\r
-                                       if (request.getClazz() == String.class) binding = Bindings.STRING;\r
-                                       if (request.getClazz() == MutableString.class) binding = Bindings.MUTABLE_STRING;\r
-                                       } else {\r
-                                               StringType type = new StringType();\r
-                                               type.setLength( length==null ? null : org.simantics.databoard.util.Range.valueOf( length.value()[0] ) );\r
-                                               type.setMimeType( mimeType==null ? null : mimeType.value() );\r
-                                               type.setPattern( pattern==null ? null : pattern.value() );                                      \r
-                                       if (request.getClazz() == String.class) binding = new StringBindingDefault(type);\r
-                                       if (request.getClazz() == MutableString.class) binding = new MutableStringBinding(type);\r
-                                       }\r
-                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());\r
-                               \r
-                   repository.put(request, binding);                        \r
-                               return binding;\r
-                       }\r
-               }\r
-\r
-               \r
-       // Custom factories\r
-        for (BindingProvider factory : subFactories) {\r
-               Binding result = factory.provideBinding(this, request);                 \r
-               if (result == null) continue;\r
-\r
-               /// Array\r
-               // If the result was an arraybinding, complete the composite binding\r
-               if (result instanceof ArrayBinding) {\r
-                       ArrayBinding binding = (ArrayBinding) result;\r
-                       ArrayType type = binding.type();\r
-               Length lengthAnnotation = request.getAnnotation(Length.class);\r
-               Arguments argumentsAnnotation = request.getAnnotation(Arguments.class);\r
-               Annotation[] componentAnnotations = request.dropAnnotations(1, lengthAnnotation);                               \r
-               Class<?> componentClass = argumentsAnnotation!=null ? argumentsAnnotation.value()[0] : request.getClazz().getComponentType();\r
-\r
-               org.simantics.databoard.util.Range[] lengths = null;\r
-               if (lengthAnnotation!=null) {\r
-                               String[] strs = lengthAnnotation.value();\r
-                               lengths = new org.simantics.databoard.util.Range[strs.length];\r
-                           for (int i=0; i<strs.length; i++)\r
-                               lengths[i] = org.simantics.databoard.util.Range.valueOf(strs[i]);                               \r
-               }\r
-               \r
-               if ( binding.componentBinding==null && request.componentBindings!=null ) binding.componentBinding = request.componentBindings[0];\r
-               if ( binding.componentBinding == null) {\r
-                       BindingRequest componentRequest = request.componentRequests != null ? request.componentRequests[0] : null;\r
-                               if (componentRequest==null) {\r
-                                       if (componentClass==null) {\r
-                                               componentClass = Object.class;\r
-                                       // throw new BindingConstructionException("Cannot determine array component type");\r
-                                       }\r
-                                       componentRequest = new BindingRequest(componentClass, componentAnnotations);                    \r
-                               }\r
-                               \r
-                               inprogress.put(request, binding);\r
-                               binding.componentBinding = construct( componentRequest );\r
-                               inprogress.remove(request);\r
-                       }\r
-               \r
-                       type.componentType = binding.componentBinding.type();\r
-               \r
-               // Multi-dimensional Array. Apply range to sub-array-types\r
-               ArrayType t = type;\r
-               if (lengths!=null) {\r
-                   for (int i=0; i<lengths.length; i++) {\r
-                       t.setLength( lengths[i] );\r
-                       if (i<lengths.length-1)\r
-                           t = (ArrayType) t.componentType;\r
-                   }\r
-               }                   \r
-               }\r
-               \r
-               /// Map\r
-            // Map Type\r
-            if ( result instanceof MapBinding ) {\r
-               MapBinding binding = (MapBinding) result;\r
-               \r
-                       Arguments argumentsAnnotation = request.getAnnotation(Arguments.class);\r
-                       Annotation[] componentAnnotations = request.dropAnnotations( 2 );\r
-                Class<?>[] arguments = argumentsAnnotation != null ? argumentsAnnotation.value() : null;\r
-\r
-                BindingRequest keyRequest = null;\r
-                BindingRequest valueRequest = null;\r
-                \r
-                Binding keyBinding = null;\r
-                Binding valueBinding = null;\r
-                       \r
-                       if (binding.getKeyBinding() != null) {\r
-                           keyBinding = binding.getKeyBinding();\r
-                       }\r
-                       else if (request.componentBindings != null) {\r
-                               keyBinding = request.componentBindings[0];\r
-                       }\r
-                       else if (request.componentRequests != null) {\r
-                               keyRequest = request.componentRequests[0];\r
-                       }\r
-                       else {\r
-                               Class<?> keyClass = arguments != null && arguments.length >= 1 ? arguments[0] : null;\r
-                    if (keyClass==null) {\r
-                       keyClass = Object.class;\r
-                       //throw new BindingConstructionException("Cannot determine key class, use @Arguments annotation");\r
-                    }\r
-                    keyRequest = new BindingRequest(keyClass, componentAnnotations);\r
-                       }\r
-                       \r
-                       if (binding.getValueBinding() != null) {\r
-                    valueBinding = binding.getValueBinding();\r
-                       }\r
-                       else if (request.componentBindings != null) {\r
-                               valueBinding = request.componentBindings[1];\r
-                       }\r
-                       else if (request.componentRequests != null) {\r
-                               valueRequest = request.componentRequests[1];\r
-                       }\r
-                       else {\r
-                               Class<?> valueClass = arguments != null && arguments.length >= 2 ? arguments[1] : null;\r
-                    if (valueClass==null) {\r
-                       valueClass = Object.class;\r
-                       //throw new BindingConstructionException("Cannot determine value class, use @Arguments annotation");\r
-                    }\r
-                    valueRequest = new BindingRequest(valueClass, componentAnnotations);\r
-                       }\r
-                       \r
-                       inprogress.put(request, result);\r
-                       if (keyRequest!=null) {\r
-                               keyBinding = construct( keyRequest );\r
-                       }\r
-                       if (valueRequest!=null) {\r
-                               valueBinding = construct( valueRequest );\r
-                       }\r
-                inprogress.remove(request);\r
-                \r
-                MapType type = binding.type();\r
-                type.keyType = keyBinding.type();\r
-                type.valueType = valueBinding.type();\r
-                       binding.setKeyBinding( keyBinding );\r
-                       binding.setValueBinding( valueBinding );\r
-            }\r
-               \r
-               /// Optional\r
-               \r
-               \r
-               /// Union\r
-               \r
-               \r
-               /// Record\r
-               \r
-               // Its complete, store to repository\r
-                       repository.put(request, result);                        \r
-               return result;\r
-        }\r
-               \r
-               \r
-        \r
-        if (request.getClazz().isEnum()) {\r
-            Enum<?>[] enums = (Enum[]) request.getClazz().getEnumConstants();\r
-            UnionType type = new UnionType();              \r
-            type.components = new Component[enums.length];\r
-            for (int i=0; i<enums.length; i++) {\r
-                String name = enums[i].name();\r
-                type.components[i] = new Component(name, new RecordType(false));                \r
-            }                              \r
-           EnumClassBinding binding = new EnumClassBinding(type, (Class<Enum<?>>) request.getClazz() );                            \r
-            repository.put(request, binding);\r
-            return binding;\r
-        }              \r
-        \r
-        // Union type\r
-        if(request.hasAnnotation(Union.class)) {\r
-               Union union = request.getAnnotation(Union.class);                       \r
-               UnionType type = new UnionType();\r
-                       UnionClassBinding binding = new UnionClassBinding(type);\r
-            Class<?>[] cases = union.value();\r
-                       int count = cases.length; \r
-            Binding[] componentBindings = new Binding[count];\r
-            type.components = new Component[ count ];\r
-            binding.componentClasses = new Class<?>[ count ];\r
-            binding.setComponentBindings(componentBindings);\r
-            \r
-                       inprogress.put(request, binding);                   \r
-            for(int i=0;i<count;++i) {\r
-               binding.componentClasses[i]= cases[i];\r
-               Component component = type.components[i] = new Component(cases[i].getSimpleName(), null /* updated later*/);\r
-               BindingRequest componentRequest = new BindingRequest( cases[i] );\r
-               Binding componentBinding = componentBindings[i] = construct( componentRequest );\r
-               component.type = componentBinding.type();                       \r
-            }\r
-            \r
-                       inprogress.remove(request);\r
-                       repository.put(request, binding);\r
-            return binding;\r
-        }\r
-        \r
-        // Record type\r
-        {\r
-               RecordType type = new RecordType();\r
-               ClassInfo ci = ClassInfo.getInfo( request.getClazz() );\r
-               boolean publicClass = Modifier.isPublic( request.getClazz().getModifiers() ); \r
-               boolean useAsmBinding = asmClassBindingFactory!=null && publicClass;\r
-               RecordBindingProvider f = useAsmBinding ? asmClassBindingFactory : refClassBindingFactory;\r
-               RecordBinding binding = f.provideRecordBinding( request.getClazz(), type);\r
-               int count = ci.fields.length;\r
-               Binding[] componentBindings = binding.getComponentBindings();                   \r
-            Component[] components = new Component[ count ];\r
-            type.setReferable( request.getAnnotation(Referable.class) != null );\r
-            type.setComponents( components );\r
-\r
-                       inprogress.put(request, binding);\r
-                       List<Integer> identifierIndices = new ArrayList<Integer>(1);\r
-            for(int i=0;i<type.getComponentCount();++i) {\r
-               Field field = ci.fields[i];\r
-               Annotation[] annotations = getFieldAnnotations(field);\r
-               Class<?> fieldClass = field.getType(); \r
-               BindingRequest componentRequest = new BindingRequest(fieldClass, annotations);\r
-               \r
-               Name nameAnnotation = componentRequest.getAnnotation( Name.class );\r
-               String fieldName = nameAnnotation!=null ? nameAnnotation.value() : field.getName();\r
-               Component c = components[i] = new Component(fieldName, null /* updated later */);\r
-               \r
-               Identifier idAnnotation = componentRequest.getAnnotation( Identifier.class );\r
-               if ( idAnnotation!=null ) {\r
-                       componentRequest.dropAnnotations(1, idAnnotation);\r
-                       identifierIndices.add( i );\r
-               }\r
-               Binding componentBinding = componentBindings[i] = construct( componentRequest );\r
-               c.type = componentBinding.type();\r
-            }\r
-            type.setIdentifiers(identifierIndices);\r
-                       inprogress.remove(request);\r
-                       repository.put(request, binding);\r
-            return binding;\r
-        }\r
-       }\r
-       \r
-       public Binding construct(BindingRequest request) \r
-       throws BindingConstructionException\r
-       {\r
-               if (failures.containsKey(request)) throw failures.get(request);\r
-               if (inprogress.containsKey(request)) return inprogress.get(request);\r
-               if (repository.containsRequest(request)) return repository.get(request);\r
-               \r
-               // Start construction\r
-               try {                   \r
-                       Binding binding = doConstruct(request);\r
-                       \r
-                       // Avoid creating duplicate binding instances\r
-                       // Only check bindings that are complete\r
-                       if (inprogress.isEmpty() || isComplete(binding, new IdentityHashSet<Binding>())) {\r
-                               Binding defaultBinding = defaultBindingFactory.getBinding(binding.type());\r
-                               if (defaultBinding != null && defaultBinding.equals(binding))\r
-                                       binding = defaultBinding;\r
-                       }\r
-                       \r
-                       repository.put(request, binding);\r
-                       \r
-                       return binding;\r
-               } catch (RangeException e) {\r
-                       inprogress.remove( request );\r
-                       BindingConstructionException bce = new BindingConstructionException( e ); \r
-                       failures.put(request, bce);\r
-                       throw bce;\r
-               } catch (BindingConstructionException e) {\r
-                       inprogress.remove( request );\r
-                       failures.put(request, e);\r
-                       throw e;\r
-               } catch (Throwable t) {\r
-                       BindingConstructionException bce = new BindingConstructionException( t );\r
-                       inprogress.remove( request );\r
-                       failures.put(request, bce);\r
-                       throw bce;\r
-               }\r
-       }\r
-       \r
-       boolean isComplete(Binding binding, IdentityHashSet<Binding> checked) {\r
-               for (Binding b : inprogress.values())\r
-                       if (b == binding) return false;\r
-               \r
-               if (checked.contains(binding)) return true;\r
-               \r
-               if (binding.getComponentCount() > 0) {\r
-                       checked.add(binding);\r
-                       for (int i = 0; i < binding.getComponentCount(); i++) {\r
-                               if (!isComplete(binding.getComponentBinding(i), checked))\r
-                                       return false;\r
-                       }\r
-               }\r
-               \r
-               return true;\r
-       }\r
-\r
-       /**\r
-        * Get a binding to a Java Class. Type details can be modified with annotations.\r
-        * Please see the package org.simantics.databoard.annotations. \r
-        * <p>\r
-        *  \r
-        * The whether the result binding is a completely mutable or not depends on the\r
-        * provided classes. For instance, fields such as Boolean, Integer, Long\r
-        * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.\r
-        * The length of Object[] is not mutable, but length of List<Object> is. <p>\r
-        * \r
-        * Note, results are stored with strong reference into the repository assigned\r
-        * to this factory.<p> \r
-        * \r
-        * @see ClassBindingFactory  \r
-        * @param clazz\r
-        * @return binding\r
-        * @throws BindingConstructionException\r
-        */\r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBinding(Class<?> clazz)\r
-    throws BindingConstructionException\r
-    {\r
-       return (T) construct( new BindingRequest(clazz) );\r
-    }\r
-    \r
-       /**\r
-        * Get a binding to a Java Class. Use this method to acquire class \r
-        * parameters for a generics class. <p>\r
-        * \r
-        * Example 1: \r
-        * \r
-        *    Binding binding = getBinding(Map.class, String.class, Integer.class);\r
-        *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();\r
-        *    \r
-        * Example 2:\r
-        *    \r
-     *  Binding d = getBinding(List.class, Integer.class);\r
-        *  List<Integer> list = (List<Integer>) d.createRandom(5);\r
-        *    \r
-        * Example 3:\r
-        *    \r
-     *  Binding d = getBinding(List.class, List.class, Integer.class);\r
-        *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);\r
-        * \r
-        * @see ClassBindingFactory  \r
-        * @param clazz\r
-        * @return binding\r
-        * @throws BindingConstructionException\r
-        */\r
-    @SuppressWarnings("unchecked")\r
-       public <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)\r
-    throws BindingConstructionException\r
-    {\r
-       Arguments args = new ArgumentImpl(parameters);\r
-       BindingRequest request = new BindingRequest( clazz, args );\r
-       return (T) construct( request );\r
-    }    \r
-       \r
-       public Binding getBinding(BindingRequest request) throws BindingConstructionException {         \r
-               return construct(request);\r
-       }\r
-       \r
-       public Binding getBindingUnchecked(BindingRequest request) throws RuntimeBindingConstructionException {\r
-               try {\r
-                       return construct(request);\r
-               } catch (BindingConstructionException e) {\r
-                       throw new RuntimeBindingConstructionException(e);\r
-               }\r
-       }       \r
-       \r
-       static Class<?>[] NO_CLASSES = new Class<?>[0];\r
-       \r
-    public static Annotation[] getFieldAnnotations(Field field) \r
-    {\r
-       Annotation[] annotations = field.getAnnotations().clone();\r
-       ArrayList<Class<?>> list = new ArrayList<Class<?>>();\r
-       getTypes( field.getGenericType(), list );\r
-       Class<?> fieldClass = list.remove(0);\r
-       Class<?>[] parameterClasses = list.isEmpty() ? NO_CLASSES : list.toArray( NO_CLASSES );\r
-       \r
-       if (Set.class.isAssignableFrom(fieldClass) && parameterClasses!=null &&parameterClasses.length==1) {\r
-               Annotation[] a2 = new Annotation[annotations.length+1];\r
-               System.arraycopy(annotations, 0, a2, 0, annotations.length);\r
-               \r
-               Class<?> keyType = parameterClasses[0];\r
-               a2[annotations.length] = new ArgumentImpl(keyType);                                             \r
-               annotations = a2;\r
-       }       \r
-       if (Map.class.isAssignableFrom(fieldClass) && parameterClasses!=null && parameterClasses.length==2) {\r
-               Annotation[] a2 = new Annotation[annotations.length+1];\r
-               System.arraycopy(annotations, 0, a2, 0, annotations.length);\r
-               \r
-               Class<?> keyType = parameterClasses[0];\r
-               Class<?> valueType = parameterClasses[1];\r
-               a2[annotations.length] = new ArgumentImpl(keyType, valueType);                                          \r
-               annotations = a2;\r
-       }       \r
-       if (List.class.isAssignableFrom(fieldClass) && parameterClasses!=null && parameterClasses.length==1) {\r
-               Annotation[] a2 = new Annotation[annotations.length+1];\r
-               System.arraycopy(annotations, 0, a2, 0, annotations.length);\r
-               Class<?> componentType = parameterClasses[0];\r
-               a2[annotations.length] = new ArgumentImpl(componentType);\r
-               annotations = a2;\r
-       }       \r
-       \r
-       if (parameterClasses!=null && parameterClasses.length>0) {\r
-               Annotation[] a2 = new Annotation[annotations.length+1];\r
-               System.arraycopy(annotations, 0, a2, 0, annotations.length);\r
-               a2[annotations.length] = new ArgumentImpl(parameterClasses);\r
-               annotations = a2;\r
-       }\r
-       \r
-       return annotations;\r
-    }\r
-    \r
-    static void getTypes(Type type, Collection<Class<?>> result) \r
-    {\r
-       if ( type instanceof Class ) {\r
-               result.add( (Class<?>) type );\r
-       } else \r
-       if ( type instanceof ParameterizedType ) {\r
-                       ParameterizedType p = (ParameterizedType) type;\r
-                       getTypes( p.getRawType(), result );\r
-               for ( Type x : p.getActualTypeArguments() ) getTypes(x, result);\r
-       } else\r
-               if ( type instanceof GenericArrayType) {\r
-                       GenericArrayType at = (GenericArrayType) type;\r
-                       Type componentType = at.getGenericComponentType();\r
-                       ArrayList<Class<?>> list = new ArrayList<Class<?>>(1);\r
-                       getTypes( componentType, list );\r
-                       // To Array class\r
-                       Object dummy = Array.newInstance(list.get(0), 0);\r
-                       result.add( dummy.getClass() ); \r
-               } else if ( type instanceof TypeVariable ) {\r
-                       result.add( Object.class );              \r
-               } else\r
-               throw new RuntimeException( type.getClass()+ " is not implemented" );\r
-    }\r
-    \r
-    /**\r
-     * Get all actual parameters types, incl. classes and generic types\r
-     * \r
-     * @param f\r
-     * @return\r
-     */\r
-       static Type[] getParameterTypes(Field f) {\r
-               Type t = f.getGenericType();\r
-               if (t==null || t instanceof ParameterizedType==false) return new Class[0];              \r
-               ParameterizedType p = (ParameterizedType) t;\r
-               return p.getActualTypeArguments();\r
-    }\r
-    \r
-\r
-}\r
+package org.simantics.databoard.binding.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.annotations.ArgumentImpl;
+import org.simantics.databoard.annotations.Arguments;
+import org.simantics.databoard.annotations.Identifier;
+import org.simantics.databoard.annotations.Length;
+import org.simantics.databoard.annotations.MIMEType;
+import org.simantics.databoard.annotations.Name;
+import org.simantics.databoard.annotations.Optional;
+import org.simantics.databoard.annotations.Pattern;
+import org.simantics.databoard.annotations.Range;
+import org.simantics.databoard.annotations.Referable;
+import org.simantics.databoard.annotations.Union;
+import org.simantics.databoard.annotations.Unit;
+import org.simantics.databoard.binding.ArrayBinding;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.MapBinding;
+import org.simantics.databoard.binding.OptionalBinding;
+import org.simantics.databoard.binding.RecordBinding;
+import org.simantics.databoard.binding.error.BindingConstructionException;
+import org.simantics.databoard.binding.error.RuntimeBindingConstructionException;
+import org.simantics.databoard.binding.factory.BindingRepository;
+import org.simantics.databoard.binding.factory.DefaultBindingFactory;
+import org.simantics.databoard.binding.factory.TypeBindingFactory;
+import org.simantics.databoard.binding.impl.ByteBindingDefault;
+import org.simantics.databoard.binding.impl.DoubleBindingDefault;
+import org.simantics.databoard.binding.impl.FloatBindingDefault;
+import org.simantics.databoard.binding.impl.IntegerBindingDefault;
+import org.simantics.databoard.binding.impl.LongBindingDefault;
+import org.simantics.databoard.binding.impl.OptionalBindingDefault;
+import org.simantics.databoard.binding.impl.StringBindingDefault;
+import org.simantics.databoard.binding.impl.UnsignedByteBinding;
+import org.simantics.databoard.binding.impl.UnsignedIntegerBinding;
+import org.simantics.databoard.binding.impl.UnsignedLongBinding;
+import org.simantics.databoard.binding.mutable.MutableByteBinding;
+import org.simantics.databoard.binding.mutable.MutableDoubleBinding;
+import org.simantics.databoard.binding.mutable.MutableFloatBinding;
+import org.simantics.databoard.binding.mutable.MutableIntegerBinding;
+import org.simantics.databoard.binding.mutable.MutableLongBinding;
+import org.simantics.databoard.binding.mutable.MutableStringBinding;
+import org.simantics.databoard.primitives.MutableBoolean;
+import org.simantics.databoard.primitives.MutableByte;
+import org.simantics.databoard.primitives.MutableDouble;
+import org.simantics.databoard.primitives.MutableFloat;
+import org.simantics.databoard.primitives.MutableInteger;
+import org.simantics.databoard.primitives.MutableLong;
+import org.simantics.databoard.primitives.MutableString;
+import org.simantics.databoard.primitives.UnsignedByte;
+import org.simantics.databoard.primitives.UnsignedInteger;
+import org.simantics.databoard.primitives.UnsignedLong;
+import org.simantics.databoard.type.ArrayType;
+import org.simantics.databoard.type.ByteType;
+import org.simantics.databoard.type.Component;
+import org.simantics.databoard.type.DoubleType;
+import org.simantics.databoard.type.FloatType;
+import org.simantics.databoard.type.IntegerType;
+import org.simantics.databoard.type.LongType;
+import org.simantics.databoard.type.MapType;
+import org.simantics.databoard.type.OptionalType;
+import org.simantics.databoard.type.RecordType;
+import org.simantics.databoard.type.StringType;
+import org.simantics.databoard.type.UnionType;
+import org.simantics.databoard.util.ArrayUtils;
+import org.simantics.databoard.util.IdentityHashSet;
+import org.simantics.databoard.util.RangeException;
+
+/**
+ * Type Factory constructs data types from reflection requests.
+ * Successfully constructed types are placed in the repository that was given 
+ * at construction time.
+ *  
+ * @author Toni Kalajainen
+ */
+public class ClassBindingFactory {
+       
+       /**
+        * Map of failed constructions. 
+        */
+       Map<BindingRequest, BindingConstructionException> failures = new HashMap<BindingRequest, BindingConstructionException>();
+       
+       /**
+        * Map that contains in incomplete constructions.
+        */
+       Map<BindingRequest, Binding> inprogress = new HashMap<BindingRequest, Binding>();
+       
+       /**
+        * Repository where successful constructions are placed. 
+        */
+       BindingRepository repository;   
+       
+       List<BindingProvider> subFactories = new CopyOnWriteArrayList<BindingProvider>();
+
+       /** Asm based binding factory for Classes, this is used if Asm library is available, else null */
+       RecordBindingProvider asmClassBindingFactory;
+       
+       /** Reflection based binding factory for Classes, this has poorer performance than asm factory */
+       RecordBindingProvider refClassBindingFactory;
+
+       /** Factory for creating default bindings for data types. */
+       TypeBindingFactory defaultBindingFactory;
+       
+       /**
+        * Construct a new reflection binding factory 
+        */
+       public ClassBindingFactory() {
+               init();
+               this.repository = new BindingRepository();
+               this.defaultBindingFactory = new DefaultBindingFactory();
+       }
+       
+       /**
+        * Construct a new reflection binding factory that places constructed 
+        * bindings into user given repository.
+        * 
+        * @param repository
+        */
+       public ClassBindingFactory(BindingRepository repository, TypeBindingFactory defaultBindingFactory) {
+               init();
+               this.repository = repository;
+               this.defaultBindingFactory = defaultBindingFactory;
+       }
+       
+       void init() {
+               refClassBindingFactory = new ReflectionBindingProvider();
+               try {
+                       // Check ASM Exists
+                       Class.forName("org.objectweb.asm.ClassWriter");
+                       // Create factory
+                       Class<?> y = Class.forName("org.simantics.databoard.binding.reflection.AsmBindingProvider");
+                       Constructor<?> c = y.getConstructor();
+                       asmClassBindingFactory = (RecordBindingProvider) c.newInstance();
+                       return;
+               } catch (ClassNotFoundException e) {
+               } catch (InstantiationException e) {
+               } catch (IllegalAccessException e) {
+               } catch (IllegalArgumentException e) {
+               } catch (InvocationTargetException e) {
+               } catch (SecurityException e) {
+               } catch (NoSuchMethodException e) {
+               }
+       }
+       
+       public void addFactory(BindingProvider factory) 
+       {
+               if (!subFactories.contains(factory)) {
+                       this.subFactories.add(factory);
+               }
+       }
+       
+       public void removeFactory(BindingProvider factory) {
+               subFactories.remove(factory);
+       }
+       
+       public BindingRepository getRepository() {
+               return repository;
+       }
+       
+       /**
+        * Constructs a binding to comply to class request.
+        * This is the method sub-classes implement. 
+        * The implementation should use the inprogress -map for construction of 
+        * bindings that have component types.
+        * 
+        *  e.g. 
+        *   inprogress.put(request, notCompletelyConstructedBinding);
+        *   Binding componentBinding = construct( componentRequest );
+        *   notCompletelyConstructedBinding.setChild( componentBinding );
+        *   inprogress.remove(request);
+        *   
+        * try-finally is not needed.
+        * 
+        * @param request
+        * @return
+        * @throws BindingConstructionException
+        * @throws RangeException
+        */
+       @SuppressWarnings("unchecked")
+    protected Binding doConstruct(BindingRequest request) throws BindingConstructionException, RangeException
+       {
+               // Optional
+       if(request.hasAnnotation(Optional.class))
+       {               
+               Optional optional = request.getAnnotation(Optional.class); 
+               Annotation[] newAnnotations = ArrayUtils.dropElements(request.annotations, optional);
+               BindingRequest componentRequest = new BindingRequest(request.getClazz(), newAnnotations);
+               OptionalType type = new OptionalType();
+               OptionalBinding binding = new OptionalBindingDefault(type, null);
+                       inprogress.put(request, binding);
+                       binding.componentBinding = construct( componentRequest );
+                       type.componentType = binding.componentBinding.type();
+                       inprogress.remove(request);
+                       
+                       return binding;
+       }
+
+            
+       
+       // Primitive
+               {               
+                       Range range = request.getAnnotation(Range.class);
+                       Unit unit = request.getAnnotation(Unit.class);
+                       
+                       if (request.getClazz() == Integer.class || request.getClazz() == int.class || request.getClazz() == MutableInteger.class || UnsignedInteger.class.isAssignableFrom(request.getClazz())) {
+                               Binding binding = null; 
+                               if (range==null && unit==null) {
+                                       if (request.getClazz() == int.class) binding = Bindings.INTEGER;
+                                       if (request.getClazz() == Integer.class) binding = Bindings.INTEGER;
+                                       if (request.getClazz() == MutableInteger.class) binding = Bindings.MUTABLE_INTEGER;
+                                       if (request.getClazz() == UnsignedInteger.Mutable.class) binding = Bindings.MUTABLE_UNSIGNED_INTEGER;
+                                       if (request.getClazz() == UnsignedInteger.Immutable.class) binding = Bindings.UNSIGNED_INTEGER;
+                               } else {
+                                       IntegerType type = new IntegerType();
+                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );
+                                       type.setUnit( unit==null ? null : unit.value() );
+
+                                       if (request.getClazz() == int.class) binding = new IntegerBindingDefault(type);
+                                       if (request.getClazz() == Integer.class) binding = new IntegerBindingDefault(type);
+                                       if (request.getClazz() == MutableInteger.class) binding = new MutableIntegerBinding(type);
+                                       if (request.getClazz() == UnsignedInteger.Mutable.class) binding = new UnsignedIntegerBinding.Mutable(type);
+                                       if (request.getClazz() == UnsignedInteger.Immutable.class) binding = new UnsignedIntegerBinding.Immutable(type);
+                               }
+                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());
+                               
+                               repository.put(request, binding);
+                               return binding;
+                       }
+                               
+                       if (request.getClazz() == Byte.class || request.getClazz() == byte.class || request.getClazz() == MutableByte.class || UnsignedByte.class.isAssignableFrom(request.getClazz())) {
+                               Binding binding = null; 
+                               if (range==null && unit==null) {
+                                       if (request.getClazz() == byte.class) binding = Bindings.BYTE;
+                                       if (request.getClazz() == Byte.class) binding = Bindings.BYTE;
+                                       if (request.getClazz() == MutableByte.class) binding = Bindings.MUTABLE_BYTE;
+                                       if (request.getClazz() == UnsignedByte.Mutable.class) binding = Bindings.MUTABLE_UNSIGNED_BYTE;
+                                       if (request.getClazz() == UnsignedByte.Immutable.class) binding = Bindings.UNSIGNED_BYTE;
+                               } else {
+                                       ByteType type = new ByteType();
+                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );
+                                       type.setUnit( unit==null ? null : unit.value() );
+
+                                       if (request.getClazz() == byte.class) binding = new ByteBindingDefault(type);
+                                       if (request.getClazz() == Byte.class) binding = new ByteBindingDefault(type);
+                                       if (request.getClazz() == MutableByte.class) binding = new MutableByteBinding(type);
+                                       if (request.getClazz() == UnsignedByte.Mutable.class) binding = new UnsignedByteBinding.Mutable(type);
+                                       if (request.getClazz() == UnsignedByte.Immutable.class) binding = new UnsignedByteBinding.Immutable(type);
+                               }
+                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());
+                               
+                               repository.put(request, binding);                       
+                               return binding;
+                       }                       
+                       
+                       if (request.getClazz() == Long.class || request.getClazz() == long.class || request.getClazz() == MutableLong.class || UnsignedLong.class.isAssignableFrom(request.getClazz())) {
+                               Binding binding = null; 
+                               if (range==null && unit==null) {
+                                       if (request.getClazz() == long.class) binding = Bindings.LONG;
+                                       if (request.getClazz() == Long.class) binding = Bindings.LONG;
+                                       if (request.getClazz() == MutableLong.class) binding = Bindings.MUTABLE_LONG;
+                                       if (request.getClazz() == UnsignedLong.Mutable.class) binding = Bindings.MUTABLE_UNSIGNED_LONG;
+                                       if (request.getClazz() == UnsignedLong.Immutable.class) binding = Bindings.UNSIGNED_LONG;
+                               } else {
+                                       LongType type = new LongType();
+                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );
+                                       type.setUnit( unit==null ? null : unit.value() );
+
+                                       if (request.getClazz() == long.class) binding = new LongBindingDefault(type);
+                                       if (request.getClazz() == Long.class) binding = new LongBindingDefault(type);
+                                       if (request.getClazz() == MutableLong.class) binding = new MutableLongBinding(type);
+                                       if (request.getClazz() == UnsignedLong.Mutable.class) binding = new UnsignedLongBinding.Mutable(type);
+                                       if (request.getClazz() == UnsignedLong.Immutable.class) binding = new UnsignedLongBinding.Immutable(type);
+                               }
+                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());
+                               
+                               repository.put(request, binding);                       
+                               return binding;
+                       }
+                       
+                       if (request.getClazz() == Float.class || request.getClazz() == float.class || request.getClazz() == MutableFloat.class) {
+                               Binding binding = null; 
+                               if (range==null && unit==null) {
+                                       if (request.getClazz() == float.class) binding = Bindings.FLOAT;
+                                       if (request.getClazz() == Float.class) binding = Bindings.FLOAT;
+                                       if (request.getClazz() == MutableFloat.class) binding = Bindings.MUTABLE_FLOAT;
+                               } else {
+                                       FloatType type = new FloatType();
+                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );
+                                       type.setUnit( unit==null ? null : unit.value() );
+
+                                       if (request.getClazz() == float.class) binding = new FloatBindingDefault(type);
+                                       if (request.getClazz() == Float.class) binding = new FloatBindingDefault(type);
+                                       if (request.getClazz() == MutableFloat.class) binding = new MutableFloatBinding(type);
+                               }
+                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());
+                               
+                               repository.put(request, binding);                       
+                               return binding;
+                       }
+                       
+                       if (request.getClazz() == Double.class || request.getClazz() == double.class || request.getClazz() == MutableDouble.class) {
+                               Binding binding = null; 
+                               if (range==null && unit==null) {
+                                       if (request.getClazz() == double.class) binding = Bindings.DOUBLE;
+                                       if (request.getClazz() == Double.class) binding = Bindings.DOUBLE;
+                                       if (request.getClazz() == MutableDouble.class) binding = Bindings.MUTABLE_DOUBLE;
+                               } else {
+                                       DoubleType type = new DoubleType();
+                                       type.setRange( range==null ? null : org.simantics.databoard.util.Range.valueOf(range.value()) );
+                                       type.setUnit( unit==null ? null : unit.value() );
+
+                                       if (request.getClazz() == double.class) binding = new DoubleBindingDefault(type);
+                                       if (request.getClazz() == Double.class) binding = new DoubleBindingDefault(type);
+                                       if (request.getClazz() == MutableDouble.class) binding = new MutableDoubleBinding(type);
+                               }
+                               
+                               repository.put(request, binding);                       
+                               return binding;
+                       }
+
+                       if (request.getClazz() == Boolean.class || request.getClazz() == boolean.class || request.getClazz() == MutableBoolean.class) {
+                               Binding binding = null;
+                       if (request.getClazz() == Boolean.class || request.getClazz() == boolean.class) binding = Bindings.BOOLEAN;
+                       if (request.getClazz() == MutableBoolean.class) binding = Bindings.MUTABLE_BOOLEAN;             
+                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());
+                               
+                               repository.put(request, binding);                       
+                               return binding;
+                       }
+
+                       if (request.getClazz() == String.class || request.getClazz() == MutableString.class) {
+                               Length length = request.getAnnotation(Length.class);
+                               MIMEType mimeType = request.getAnnotation(MIMEType.class);
+                               Pattern pattern = request.getAnnotation(Pattern.class);
+                               Binding binding = null;
+                               if (length==null && mimeType==null && pattern==null) {
+                                       if (request.getClazz() == String.class) binding = Bindings.STRING;
+                                       if (request.getClazz() == MutableString.class) binding = Bindings.MUTABLE_STRING;
+                                       } else {
+                                               StringType type = new StringType();
+                                               type.setLength( length==null ? null : org.simantics.databoard.util.Range.valueOf( length.value()[0] ) );
+                                               type.setMimeType( mimeType==null ? null : mimeType.value() );
+                                               type.setPattern( pattern==null ? null : pattern.value() );                                      
+                                       if (request.getClazz() == String.class) binding = new StringBindingDefault(type);
+                                       if (request.getClazz() == MutableString.class) binding = new MutableStringBinding(type);
+                                       }
+                               if (binding==null) throw new BindingConstructionException("Cannot bind to "+request.getClazz().getSimpleName());
+                               
+                   repository.put(request, binding);                        
+                               return binding;
+                       }
+               }
+
+               
+       // Custom factories
+        for (BindingProvider factory : subFactories) {
+               Binding result = factory.provideBinding(this, request);                 
+               if (result == null) continue;
+
+               /// Array
+               // If the result was an arraybinding, complete the composite binding
+               if (result instanceof ArrayBinding) {
+                       ArrayBinding binding = (ArrayBinding) result;
+                       ArrayType type = binding.type();
+               Length lengthAnnotation = request.getAnnotation(Length.class);
+               Arguments argumentsAnnotation = request.getAnnotation(Arguments.class);
+               Annotation[] componentAnnotations = request.dropAnnotations(1, lengthAnnotation);                               
+               Class<?> componentClass = argumentsAnnotation!=null ? argumentsAnnotation.value()[0] : request.getClazz().getComponentType();
+
+               org.simantics.databoard.util.Range[] lengths = null;
+               if (lengthAnnotation!=null) {
+                               String[] strs = lengthAnnotation.value();
+                               lengths = new org.simantics.databoard.util.Range[strs.length];
+                           for (int i=0; i<strs.length; i++)
+                               lengths[i] = org.simantics.databoard.util.Range.valueOf(strs[i]);                               
+               }
+               
+               if ( binding.componentBinding==null && request.componentBindings!=null ) binding.componentBinding = request.componentBindings[0];
+               if ( binding.componentBinding == null) {
+                       BindingRequest componentRequest = request.componentRequests != null ? request.componentRequests[0] : null;
+                               if (componentRequest==null) {
+                                       if (componentClass==null) {
+                                               componentClass = Object.class;
+                                       // throw new BindingConstructionException("Cannot determine array component type");
+                                       }
+                                       componentRequest = new BindingRequest(componentClass, componentAnnotations);                    
+                               }
+                               
+                               inprogress.put(request, binding);
+                               binding.componentBinding = construct( componentRequest );
+                               inprogress.remove(request);
+                       }
+               
+                       type.componentType = binding.componentBinding.type();
+               
+               // Multi-dimensional Array. Apply range to sub-array-types
+               ArrayType t = type;
+               if (lengths!=null) {
+                   for (int i=0; i<lengths.length; i++) {
+                       t.setLength( lengths[i] );
+                       if (i<lengths.length-1)
+                           t = (ArrayType) t.componentType;
+                   }
+               }                   
+               }
+               
+               /// Map
+            // Map Type
+            if ( result instanceof MapBinding ) {
+               MapBinding binding = (MapBinding) result;
+               
+                       Arguments argumentsAnnotation = request.getAnnotation(Arguments.class);
+                       Annotation[] componentAnnotations = request.dropAnnotations( 2 );
+                Class<?>[] arguments = argumentsAnnotation != null ? argumentsAnnotation.value() : null;
+
+                BindingRequest keyRequest = null;
+                BindingRequest valueRequest = null;
+                
+                Binding keyBinding = null;
+                Binding valueBinding = null;
+                       
+                       if (binding.getKeyBinding() != null) {
+                           keyBinding = binding.getKeyBinding();
+                       }
+                       else if (request.componentBindings != null) {
+                               keyBinding = request.componentBindings[0];
+                       }
+                       else if (request.componentRequests != null) {
+                               keyRequest = request.componentRequests[0];
+                       }
+                       else {
+                               Class<?> keyClass = arguments != null && arguments.length >= 1 ? arguments[0] : null;
+                    if (keyClass==null) {
+                       keyClass = Object.class;
+                       //throw new BindingConstructionException("Cannot determine key class, use @Arguments annotation");
+                    }
+                    keyRequest = new BindingRequest(keyClass, componentAnnotations);
+                       }
+                       
+                       if (binding.getValueBinding() != null) {
+                    valueBinding = binding.getValueBinding();
+                       }
+                       else if (request.componentBindings != null) {
+                               valueBinding = request.componentBindings[1];
+                       }
+                       else if (request.componentRequests != null) {
+                               valueRequest = request.componentRequests[1];
+                       }
+                       else {
+                               Class<?> valueClass = arguments != null && arguments.length >= 2 ? arguments[1] : null;
+                    if (valueClass==null) {
+                       valueClass = Object.class;
+                       //throw new BindingConstructionException("Cannot determine value class, use @Arguments annotation");
+                    }
+                    valueRequest = new BindingRequest(valueClass, componentAnnotations);
+                       }
+                       
+                       inprogress.put(request, result);
+                       if (keyRequest!=null) {
+                               keyBinding = construct( keyRequest );
+                       }
+                       if (valueRequest!=null) {
+                               valueBinding = construct( valueRequest );
+                       }
+                inprogress.remove(request);
+                
+                MapType type = binding.type();
+                type.keyType = keyBinding.type();
+                type.valueType = valueBinding.type();
+                       binding.setKeyBinding( keyBinding );
+                       binding.setValueBinding( valueBinding );
+            }
+               
+               /// Optional
+               
+               
+               /// Union
+               
+               
+               /// Record
+               
+               // Its complete, store to repository
+                       repository.put(request, result);                        
+               return result;
+        }
+               
+               
+        
+        if (request.getClazz().isEnum()) {
+            Enum<?>[] enums = (Enum[]) request.getClazz().getEnumConstants();
+            UnionType type = new UnionType();              
+            type.components = new Component[enums.length];
+            for (int i=0; i<enums.length; i++) {
+                String name = enums[i].name();
+                type.components[i] = new Component(name, new RecordType(false));                
+            }                              
+           EnumClassBinding binding = new EnumClassBinding(type, (Class<Enum<?>>) request.getClazz() );                            
+            repository.put(request, binding);
+            return binding;
+        }              
+        
+        // Union type
+        if(request.hasAnnotation(Union.class)) {
+               Union union = request.getAnnotation(Union.class);                       
+               UnionType type = new UnionType();
+                       UnionClassBinding binding = new UnionClassBinding(type);
+            Class<?>[] cases = union.value();
+                       int count = cases.length; 
+            Binding[] componentBindings = new Binding[count];
+            type.components = new Component[ count ];
+            binding.componentClasses = new Class<?>[ count ];
+            binding.setComponentBindings(componentBindings);
+            
+                       inprogress.put(request, binding);                   
+            for(int i=0;i<count;++i) {
+               binding.componentClasses[i]= cases[i];
+               Component component = type.components[i] = new Component(cases[i].getSimpleName(), null /* updated later*/);
+               BindingRequest componentRequest = new BindingRequest( cases[i] );
+               Binding componentBinding = componentBindings[i] = construct( componentRequest );
+               component.type = componentBinding.type();                       
+            }
+            
+                       inprogress.remove(request);
+                       repository.put(request, binding);
+            return binding;
+        }
+        
+        // Record type
+        {
+               RecordType type = new RecordType();
+               ClassInfo ci = ClassInfo.getInfo( request.getClazz() );
+               boolean publicClass = Modifier.isPublic( request.getClazz().getModifiers() ); 
+               boolean useAsmBinding = asmClassBindingFactory!=null && publicClass;
+               RecordBindingProvider f = useAsmBinding ? asmClassBindingFactory : refClassBindingFactory;
+               RecordBinding binding = f.provideRecordBinding( request.getClazz(), type);
+               int count = ci.fields.length;
+               Binding[] componentBindings = binding.getComponentBindings();                   
+            Component[] components = new Component[ count ];
+            type.setReferable( request.getAnnotation(Referable.class) != null );
+            type.setComponents( components );
+
+                       inprogress.put(request, binding);
+                       List<Integer> identifierIndices = new ArrayList<Integer>(1);
+            for(int i=0;i<type.getComponentCount();++i) {
+               Field field = ci.fields[i];
+               Annotation[] annotations = getFieldAnnotations(field);
+               Class<?> fieldClass = field.getType(); 
+               BindingRequest componentRequest = new BindingRequest(fieldClass, annotations);
+               
+               Name nameAnnotation = componentRequest.getAnnotation( Name.class );
+               String fieldName = nameAnnotation!=null ? nameAnnotation.value() : field.getName();
+               Component c = components[i] = new Component(fieldName, null /* updated later */);
+               
+               Identifier idAnnotation = componentRequest.getAnnotation( Identifier.class );
+               if ( idAnnotation!=null ) {
+                       componentRequest.dropAnnotations(1, idAnnotation);
+                       identifierIndices.add( i );
+               }
+               Binding componentBinding = componentBindings[i] = construct( componentRequest );
+               c.type = componentBinding.type();
+            }
+            type.setIdentifiers(identifierIndices);
+                       inprogress.remove(request);
+                       repository.put(request, binding);
+            return binding;
+        }
+       }
+       
+       public Binding construct(BindingRequest request) 
+       throws BindingConstructionException
+       {
+               if (failures.containsKey(request)) throw failures.get(request);
+               if (inprogress.containsKey(request)) return inprogress.get(request);
+               if (repository.containsRequest(request)) return repository.get(request);
+               
+               // Start construction
+               try {                   
+                       Binding binding = doConstruct(request);
+                       
+                       // Avoid creating duplicate binding instances
+                       // Only check bindings that are complete
+                       if (inprogress.isEmpty() || isComplete(binding, new IdentityHashSet<Binding>())) {
+                               Binding defaultBinding = defaultBindingFactory.getBinding(binding.type());
+                               if (defaultBinding != null && defaultBinding.equals(binding))
+                                       binding = defaultBinding;
+                       }
+                       
+                       repository.put(request, binding);
+                       
+                       return binding;
+               } catch (RangeException e) {
+                       inprogress.remove( request );
+                       BindingConstructionException bce = new BindingConstructionException( e ); 
+                       failures.put(request, bce);
+                       throw bce;
+               } catch (BindingConstructionException e) {
+                       inprogress.remove( request );
+                       failures.put(request, e);
+                       throw e;
+               } catch (Throwable t) {
+                       BindingConstructionException bce = new BindingConstructionException( t );
+                       inprogress.remove( request );
+                       failures.put(request, bce);
+                       throw bce;
+               }
+       }
+       
+       boolean isComplete(Binding binding, IdentityHashSet<Binding> checked) {
+               for (Binding b : inprogress.values())
+                       if (b == binding) return false;
+               
+               if (checked.contains(binding)) return true;
+               
+               if (binding.getComponentCount() > 0) {
+                       checked.add(binding);
+                       for (int i = 0; i < binding.getComponentCount(); i++) {
+                               if (!isComplete(binding.getComponentBinding(i), checked))
+                                       return false;
+                       }
+               }
+               
+               return true;
+       }
+
+       /**
+        * Get a binding to a Java Class. Type details can be modified with annotations.
+        * Please see the package org.simantics.databoard.annotations. 
+        * <p>
+        *  
+        * The whether the result binding is a completely mutable or not depends on the
+        * provided classes. For instance, fields such as Boolean, Integer, Long
+        * are not mutable, instead MutableBoolean, MutableInteger and MutableLong are.
+        * The length of Object[] is not mutable, but length of List<Object> is. <p>
+        * 
+        * Note, results are stored with strong reference into the repository assigned
+        * to this factory.<p> 
+        * 
+        * @see ClassBindingFactory  
+        * @param clazz
+        * @return binding
+        * @throws BindingConstructionException
+        */
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBinding(Class<?> clazz)
+    throws BindingConstructionException
+    {
+       return (T) construct( new BindingRequest(clazz) );
+    }
+    
+       /**
+        * Get a binding to a Java Class. Use this method to acquire class 
+        * parameters for a generics class. <p>
+        * 
+        * Example 1: 
+        * 
+        *    Binding binding = getBinding(Map.class, String.class, Integer.class);
+        *    Map<String, Integer> map = (Map<String, Integer>) binding.createDefault();
+        *    
+        * Example 2:
+        *    
+     *  Binding d = getBinding(List.class, Integer.class);
+        *  List<Integer> list = (List<Integer>) d.createRandom(5);
+        *    
+        * Example 3:
+        *    
+     *  Binding d = getBinding(List.class, List.class, Integer.class);
+        *  List<List<Integer>> list = (List<List<Integer>>) d.createRandom(5);
+        * 
+        * @see ClassBindingFactory  
+        * @param clazz
+        * @return binding
+        * @throws BindingConstructionException
+        */
+    @SuppressWarnings("unchecked")
+       public <T extends Binding> T getBinding(Class<?> clazz, Class<?>...parameters)
+    throws BindingConstructionException
+    {
+       Arguments args = new ArgumentImpl(parameters);
+       BindingRequest request = new BindingRequest( clazz, args );
+       return (T) construct( request );
+    }    
+       
+       public Binding getBinding(BindingRequest request) throws BindingConstructionException {         
+               return construct(request);
+       }
+       
+       public Binding getBindingUnchecked(BindingRequest request) throws RuntimeBindingConstructionException {
+               try {
+                       return construct(request);
+               } catch (BindingConstructionException e) {
+                       throw new RuntimeBindingConstructionException(e);
+               }
+       }       
+       
+       static Class<?>[] NO_CLASSES = new Class<?>[0];
+       
+    public static Annotation[] getFieldAnnotations(Field field) 
+    {
+       Annotation[] annotations = field.getAnnotations().clone();
+       ArrayList<Class<?>> list = new ArrayList<Class<?>>();
+       getTypes( field.getGenericType(), list );
+       Class<?> fieldClass = list.remove(0);
+       Class<?>[] parameterClasses = list.isEmpty() ? NO_CLASSES : list.toArray( NO_CLASSES );
+       
+       if (Set.class.isAssignableFrom(fieldClass) && parameterClasses!=null &&parameterClasses.length==1) {
+               Annotation[] a2 = new Annotation[annotations.length+1];
+               System.arraycopy(annotations, 0, a2, 0, annotations.length);
+               
+               Class<?> keyType = parameterClasses[0];
+               a2[annotations.length] = new ArgumentImpl(keyType);                                             
+               annotations = a2;
+       }       
+       if (Map.class.isAssignableFrom(fieldClass) && parameterClasses!=null && parameterClasses.length==2) {
+               Annotation[] a2 = new Annotation[annotations.length+1];
+               System.arraycopy(annotations, 0, a2, 0, annotations.length);
+               
+               Class<?> keyType = parameterClasses[0];
+               Class<?> valueType = parameterClasses[1];
+               a2[annotations.length] = new ArgumentImpl(keyType, valueType);                                          
+               annotations = a2;
+       }       
+       if (List.class.isAssignableFrom(fieldClass) && parameterClasses!=null && parameterClasses.length==1) {
+               Annotation[] a2 = new Annotation[annotations.length+1];
+               System.arraycopy(annotations, 0, a2, 0, annotations.length);
+               Class<?> componentType = parameterClasses[0];
+               a2[annotations.length] = new ArgumentImpl(componentType);
+               annotations = a2;
+       }       
+       
+       if (parameterClasses!=null && parameterClasses.length>0) {
+               Annotation[] a2 = new Annotation[annotations.length+1];
+               System.arraycopy(annotations, 0, a2, 0, annotations.length);
+               a2[annotations.length] = new ArgumentImpl(parameterClasses);
+               annotations = a2;
+       }
+       
+       return annotations;
+    }
+    
+    static void getTypes(Type type, Collection<Class<?>> result) 
+    {
+       if ( type instanceof Class ) {
+               result.add( (Class<?>) type );
+       } else 
+       if ( type instanceof ParameterizedType ) {
+                       ParameterizedType p = (ParameterizedType) type;
+                       getTypes( p.getRawType(), result );
+               for ( Type x : p.getActualTypeArguments() ) getTypes(x, result);
+       } else
+               if ( type instanceof GenericArrayType) {
+                       GenericArrayType at = (GenericArrayType) type;
+                       Type componentType = at.getGenericComponentType();
+                       ArrayList<Class<?>> list = new ArrayList<Class<?>>(1);
+                       getTypes( componentType, list );
+                       // To Array class
+                       Object dummy = Array.newInstance(list.get(0), 0);
+                       result.add( dummy.getClass() ); 
+               } else if ( type instanceof TypeVariable ) {
+                       result.add( Object.class );              
+               } else
+               throw new RuntimeException( type.getClass()+ " is not implemented" );
+    }
+    
+    /**
+     * Get all actual parameters types, incl. classes and generic types
+     * 
+     * @param f
+     * @return
+     */
+       static Type[] getParameterTypes(Field f) {
+               Type t = f.getGenericType();
+               if (t==null || t instanceof ParameterizedType==false) return new Class[0];              
+               ParameterizedType p = (ParameterizedType) t;
+               return p.getActualTypeArguments();
+    }
+    
+
+}