class ReflectionSerializer {

    private static final ReflectionSerializer instance = new ReflectionSerializer();

    public static ReflectionSerializer getInstance() {
        return instance;
    }

    private final Map<Class, Map<String, Field>> reflectionCache = new ConcurrentHashMap<>();

    private ReflectionSerializer() {

    }

    public Set<String> getFields(Object object) {

        if (!reflectionCache.containsKey(object.getClass())) {

            Map<String, Field> fields = new HashMap<>();
            Set<Field> allFields = new HashSet<>();

            Class<?> classToExtractFieldsFrom = object.getClass();
            while (!classToExtractFieldsFrom.equals(Object.class)) {
                allFields.addAll(Arrays.asList(classToExtractFieldsFrom.getDeclaredFields()));
                classToExtractFieldsFrom = classToExtractFieldsFrom.getSuperclass();
            }

            for (Field field : allFields) {
                if ("serialVersionUID".equals(field.getName()) || "serializableFields".equals(field.getName())) {
                    continue;
                }
                if (field.isSynthetic() || "$VRc".equals(field.getName())) { //from emma
                    continue;
                }

                fields.put(field.getName(), field);
                field.setAccessible(true);
            }

            reflectionCache.put(object.getClass(), fields);
        }

        return reflectionCache.get(object.getClass()).keySet();
    }

    private Field findField(Object object, String field) {
        Field foundField = null;
        Class<?> classToCheck = object.getClass();
        while ((foundField == null) && !classToCheck.equals(Object.class)) {
            try {
                foundField = classToCheck.getDeclaredField(field);
            } catch (NoSuchFieldException e) {
                classToCheck = classToCheck.getSuperclass();
            }
        }
        if (foundField == null) {
            throw new UnexpectedLiquibaseException("No field " + field + " on " + object.getClass());
        }
        return foundField;
    }

    public Object getValue(Object object, String field) {<FILL_FUNCTION_BODY>}

    public void setValue(Object object, String field, Object value) {
        try {
            Field foundField = findField(object, field);
            foundField.setAccessible(true);

            foundField.set(object, value);
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException(e);
        }
    }

    public Class getDataTypeClass(Object object, String field) {
        try {
            Field foundField = findField(object, field);
            Type dataType = foundField.getGenericType();
            if (dataType instanceof Class) {
                return (Class) dataType;
            }
            if (dataType instanceof ParameterizedType) {
                return (Class) ((ParameterizedType) dataType).getRawType();
            }
            return Object.class;
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException(e);
        }
    }

    public Type[] getDataTypeClassParameters(Object object, String field) {
        try {
            Field foundField = findField(object, field);
            Type dataType = foundField.getGenericType();
            if (dataType instanceof ParameterizedType) {
                return ((ParameterizedType) dataType).getActualTypeArguments();
            }
            return new Type[0];
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException(e);
        }
    }
}

        if (!reflectionCache.containsKey(object.getClass())) {
            getFields(object); //fills cache
        }

        Map<String, Field> fieldsByName = reflectionCache.get(object.getClass());
        Field foundField = fieldsByName.get(field);

        try {
            if (foundField == null) {
                foundField = findField(object, field);
                foundField.setAccessible(true);

                fieldsByName.put(field, foundField);
            }

            return foundField.get(object);
        } catch (Exception e) {
            throw new UnexpectedLiquibaseException(e);
        }
    
<no_super_class>