Я думаю, что "не тратить циклы" чрезмерно инженерно.Это может быть верным утверждением, если вы сериализуете миллион объектов в секунду.В противном случае JVM оптимизирует «горячую точку» для вас.И в любом случае, это не будет узким местом в архитектуре вашего приложения.
Если вы знаете, что у ваших сущностей есть общее поле «дочерний» массив, вы можете применить один и тот же JsonSerializer
ко всем из них.просто присваивая Map
совместимых классов.
Вы должны понимать, что у Джексона есть свои ограничения.Если вам нужно что-то большее, вам может потребоваться полностью индивидуальное решение.Это лучшее, что вы можете получить с Джексоном.
Надеюсь, что ответ удовлетворительный.
Вы можете использовать пользовательский JsonSerializer<T>
.
class EntitySerializer extends StdSerializer<Entity> {
private static final long serialVersionUID = 1L;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
EntitySerializer() {
super(Entity.class);
}
@Override
public void serialize(
final Entity value,
final JsonGenerator generator,
final SerializerProvider provider) throws IOException {
final TreeNode jsonNode = OBJECT_MAPPER.valueToTree(value);
if (!AuthUtils.allowed("ChildView")) {
final TreeNode children = jsonNode.get("children");
if (children.isArray()) {
((ContainerNode<ArrayNode>) children).removeAll();
}
}
generator.writeTree(jsonNode);
}
}
Однако, как выВы можете видеть, что мы используем ObjectMapper
экземпляр внутри нашего JsonSerializer
(или вы бы предпочли вручную «писать» каждое поле с помощью JsonGenerator
? Я так не думаю: P).Поскольку ObjectMapper
ищет аннотации, чтобы избежать бесконечной рекурсии процесса сериализации, вы должны отбросить аннотацию класса
@JsonSerialize(using = EntitySerializer.class)
и вручную зарегистрировать пользовательский JsonSerializer
в Jackson ObjectMapper
.
final SimpleModule module = new SimpleModule();
module.setSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(
final SerializationConfig config,
final BeanDescription beanDesc,
final JsonSerializer<?> serializer) {
final Class<?> beanClass = beanDesc.getBeanClass();
return beanClass == Entity.class ? new EntitySerializer() : serializer;
}
});
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
Наконец, вам просто нужно использовать ObjectMapper
, или позволить вашей платформе использовать его.
Поскольку вы используете Spring, вы можете зарегистрировать @Bean
типа ObjectMapper, помеченного как @Primary
, или вы можете зарегистрировать @Bean
типа Jackson2ObjectMapperBuilder
.
Предыдущий ответ.
Поскольку метод allowed
является статическим,это означает, что к нему можно получить доступ "везде".Немного поиграв с Джексоном, я дам вам первый из двух вариантов, так как я все еще работаю над вторым.
Аннотируйте свой класс с помощью
@JsonSerialize(converter = EntityConverter.class)
public class Entity { ... }
Здесь вы указываете пользовательскую Converter
.
Реализация Converter
довольно аккуратная.
Внутри статического блока я просто получаю значение аннотации Auth
, но это необязательно,Вы можете делать то, что, по вашему мнению, лучше всего подходит для использования.
class EntityConverter extends StdConverter<Entity, Entity> {
private static final String AUTH_VALUE;
static {
final String value;
try {
final Field children = Entity.class.getDeclaredField("children");
final AuthSerialize auth = children.getAnnotation(AuthSerialize.class);
value = auth != null ? auth.value() : null;
} catch (final NoSuchFieldException e) {
// Provide appropriate Exception, or handle it
throw new RuntimeException(e);
}
AUTH_VALUE = value;
}
@Override
public Entity convert(final Entity value) {
if (AUTH_VALUE != null) {
if (!AuthUtils.allowed(AUTH_VALUE)) {
value.children.clear();
}
}
return value;
}
}
Дайте мне знать, достаточно ли этого, или вы бы предпочли более сложное решение.