/**
   * Returns the adapter corresponding to a specific type.
   *
   * @param type
   * @return
   */
  public Class<? extends IAdapter> getAdapter(Class<?> type) throws AdapterInitializationException {
    // match adapter
    if (!this.adapterMap.containsKey(type)) {
      for (Map.Entry<Class<?>, Class<? extends IAdapter>> adapterEntry :
          this.adapterMap.entrySet()) {
        if (!this.isWildcardAdapter(adapterEntry.getValue())) continue;

        // get definition
        AdapterDefinition definition =
            adapterEntry.getValue().getAnnotation(AdapterDefinition.class);

        // check input
        if (definition.input().isAssignableFrom(type)) return adapterEntry.getValue();
      }
    }

    // get fallback adapter
    if (!type.isPrimitive() && !this.adapterMap.containsKey(type)) return ObjectAdapter.class;

    // verify
    if (!this.adapterMap.containsKey(type))
      throw new AdapterInitializationException(
          "Could not find the appropriate adapter for type " + type.getName());

    // return explicit adapter
    return this.adapterMap.get(type);
  }
 /**
  * Verifies an adapter class.
  *
  * @param adapter
  * @throws AdapterInitializationException
  */
 public void verifyTypeAdapter(Class<? extends ITypeAdapter> adapter)
     throws AdapterInitializationException {
   if (!adapter.isAnnotationPresent(TypeAdapterDefinition.class))
     throw new AdapterInitializationException(
         "Cannot initialize adapter of type "
             + adapter.getName()
             + ": Missing @TypeAdapterDefinition annotation");
 }
 /**
  * Verifies an adapter class.
  *
  * @param adapter
  * @throws AdapterInitializationException
  */
 public void verifyAdapter(Class<? extends IAdapter> adapter)
     throws AdapterInitializationException {
   Preconditions.checkNotNull(adapter, "adapter");
   if (!adapter.isAnnotationPresent(AdapterDefinition.class))
     throw new AdapterInitializationException(
         "Cannot initialize adapter of type "
             + adapter.getName()
             + ": Missing @AdapterDefinition annotation");
 }
  /**
   * Checks whether an adapter will match it's children.
   *
   * @param adapter
   * @return
   * @throws AdapterInitializationException
   */
  public boolean isWildcardAdapter(Class<? extends IAdapter> adapter)
      throws AdapterInitializationException {
    this.verifyAdapter(adapter);

    // get annotation
    return adapter.getAnnotation(AdapterDefinition.class).matchChildren();
  }
  /**
   * Checks whether the adapter is sharable.
   *
   * @param adapter
   * @return
   * @throws AdapterInitializationException
   */
  public boolean isTypeAdapterSharable(Class<? extends ITypeAdapter> adapter)
      throws AdapterInitializationException {
    this.verifyTypeAdapter(adapter);

    // check
    return adapter.getAnnotation(TypeAdapterDefinition.class).sharable();
  }
  /** {@inheritDoc} */
  @Override
  public void registerAdapter(Class<? extends IAdapter> adapter) throws ConfigurationException {
    this.verifyAdapter(adapter);

    // get annotation
    AdapterDefinition definition = adapter.getAnnotation(AdapterDefinition.class);

    // register adapter
    this.adapterMap.put(definition.input(), adapter);
  }
  /**
   * Constructs a new ConfigurationProcessor.
   *
   * @param processor
   */
  public AbstractMarshaller(ConfigurationProcessor processor, Class<T> type)
      throws ConfigurationException {
    this.processor = processor;

    // verify class
    if (!type.isAnnotationPresent(Configuration.class))
      throw new ConfigurationSetupException(
          "The supplied object is not setup for configuration marshalling.");

    // store arguments
    this.type = type;
    this.typeConfiguration = type.getAnnotation(Configuration.class);

    // create instances
    this.adapterMap = new HashMap<>();
    this.typeAdapterMap = new HashMap<>();
    this.adapterInstanceMap = new HashMap<>();
    this.typeAdapterInstanceMap = new HashMap<>();

    // register defaults
    this.registerAdapters();
  }