code: @SuppressWarnings({ "unchecked", "rawtypes" })
    private ValueConverter<?, ?> addConverterInternal(ValueConverter<?, ?> converter) {
  
      getInitializationState().requireNotInitilized();
      Class<?> targetType = converter.getTargetType();
      TargetClass2ConverterMap map;
      if (targetType.isArray()) {
        map = this.targetArrayClass2converterMap;
        targetType = targetType.getComponentType();
      } else {
        map = this.targetClass2converterMap;
      }
      ComposedTargetTypeConverter targetConverter = map.get(targetType);
      if ((targetConverter == null) || !targetType.equals(targetConverter.getTargetType())) {
        // if targetConverter is NOT null here, then a ValueConverter for a more
        // specific (e.g. String or Integer) type than targetType (e.g. Object or
        // Number) is currently registered here and will therefore be replaced by
        // the new more general ValueConverter
        targetConverter = new ComposedTargetTypeConverter(targetType);
        map.put(targetType, targetConverter);
      }
      return targetConverter.addConverter(converter);
    }
docs: This method registers the given {@code converter} to this composed converter.
  
  @param converter is the converter to add.
  @return the converter with the same {@link ValueConverter#getSourceType() source-type} and
  {@link ValueConverter#getTargetType() target-type} that has been replaced by {@code converter} or
  {@code null} if no converter has been replaced.