class TypeDecoder {

    static <T extends NumericType> T decodeNumeric(String input, Class<T> type) {
        try {
            byte[] inputByteArray = Numeric.hexStringToByteArray(input);
            int typeLengthAsBytes = getTypeLengthInBytes(type);

            byte[] resultByteArray = new byte[typeLengthAsBytes + 1];

            if (Int.class.isAssignableFrom(type) || Fixed.class.isAssignableFrom(type)) {
                resultByteArray[0] = inputByteArray[0];  // take MSB as sign bit
            }

            int valueOffset = Type.MAX_BYTE_LENGTH - typeLengthAsBytes;
            System.arraycopy(inputByteArray, valueOffset, resultByteArray, 1, typeLengthAsBytes);

            BigInteger numericValue = new BigInteger(resultByteArray);
            return type.getConstructor(BigInteger.class).newInstance(numericValue);

        } catch (NoSuchMethodException e) {
            return throwUnsupportedOperation(e, type);
        } catch (SecurityException e) {
            return throwUnsupportedOperation(e, type);
        } catch (InstantiationException e) {
            return throwUnsupportedOperation(e, type);
        } catch (IllegalAccessException e) {
            return throwUnsupportedOperation(e, type);
        } catch (IllegalArgumentException e) {
            return throwUnsupportedOperation(e, type);
        } catch (InvocationTargetException e) {
            return throwUnsupportedOperation(e, type);
        }
    }

}