对于Jackson,如何安全地共享ObjectMapper?是否有任何不可变的ObjectMapper?

时间:2017-04-26 07:52:38

标签: java json jackson jackson-databind

映射器实例完全是线程安全的,不需要为单次使用创建映射器,但可以更改映射器的配置。

虽然ObjectMapper具有copy函数来复制基于exists mapper的自定义配置,但如果我共享一个映射器,则无法保证当有人想要自定义映射器时,他们将复制共享映射器。所以我想要一个不可变的映射器来共享,如果有人意外地改变了共享映射器,那么应​​该抛出一些异常。

有类似的东西吗?

2 个答案:

答案 0 :(得分:0)

一种方法是不共享ObjectMapper实例,而是正确配置它,然后共享由ObjectWriter创建的ObjectReaderObjectMapper的实例。

ObjectMapper om = new ObjectMapper();
// Configure to your needs
om.enable(...);
om.disable(...);

// Distribute these to the parts of the program where you fear configuration changes.
ObjectWriter writer = om.writer();
ObjectReader reader = om.reader();

这似乎也是杰克逊开发商所青睐的方法:https://stackoverflow.com/a/3909846/13075

答案 1 :(得分:-1)

写一个不可变的包装器比我用cglib

更容易
/**
 * Create a immutable mapper, will hide some config change operation
 */
@SuppressWarnings("unchecked")
static <T extends ObjectMapper> T immutable(T mapper) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(ObjectMapper.class);
    enhancer.setCallback((InvocationHandler) (proxy, method, args) -> {
        if (Modifier.isPublic(method.getModifiers())) {
            // banned operation
            String name = method.getName();
            boolean match = name.startsWith("set") ||
                name.startsWith("add") ||
                name.startsWith("clear") ||
                name.startsWith("disable") ||
                name.startsWith("enable") ||
                name.startsWith("register") ||
                name.startsWith("config");

            if (match) {
                throw new UnsupportedOperationException(
                    "Can not modify the immutable mapper, copy the mapper first");
            }
        }
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        return method.invoke(mapper, args);
    });
    return (T) enhancer.create();
}

因为来自mapper的配置是不可变的,所以我不需要隐藏getter。