春天蒙戈只写场

基里尔西蒙诺夫:

我有一个描述文件蒙哥一个抽象类。有可能是需要覆盖的抽象方法此类的不同实现。下面是一个简化的例子:

@Document
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public abstract class Entity {

    @Id
    private ObjectId id;

    abstract String getSomething();
}

我要getSomething()被写入到文件作为串场。我不想读回

我试着使用@AccessType注释:

@AccessType(AccessType.Type.PROPERTY)
abstract String getSomething();

但是,当我从数据库中读取这个文件,春天抛出UnsupportedOperationException: No accessor to set property它试图找到这个领域的二传手,但我不想定义setter它-该方法可以返回一个计算值,并应该没有改变它的能力。虽然空setter方法可以帮助,它看起来更像是一个解决办法,我会尽量避免它。

所以我想知道如果有一种方法从数据库中读取时跳过这个特殊的财产?相反的东西向@Transient注解。或类似@JsonIgnore的杰克逊库。

基里尔西蒙诺夫:

出人意料的是,没有简单的解决方案,以只字段的写入。

虽然创建一个空的setter方法可以解决这个问题,我觉得,它打破了最小惊讶原则:如果你有一个二传手,你还指望它来设置一个值。

所以我决定创建自己的@WriteOnly注解,并用它忽略场我不想从数据库中读取:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface WriteOnly {
}

要使用它,你将需要扩展一个AbstractMongoEventListener

@Service
public class WriteOnlyListener extends AbstractMongoEventListener<Entity> {

    @Override
    public void onAfterLoad(AfterLoadEvent<Entity> event) {
        Document doc = event.getDocument();
        if (doc == null) return;
        for (Field field: getWriteOnly(event.getType(), Class::getDeclaredFields)) {
            doc.remove(field.getName());
        }
        for (Method method: getWriteOnly(event.getType(), Class::getDeclaredMethods)) {
            doc.remove(getFieldName(method.getName()));
        }
    }

    private <T extends AccessibleObject> List<T> getWriteOnly(Class<?> type, 
                                                              Function<Class<?>, T[]> extractor) {
        List<T> list = new ArrayList<>();
        for (Class<?> c = type; c != null; c = c.getSuperclass()) {
            list.addAll(Arrays.stream(extractor.apply(c))
                    .filter(o -> o.isAnnotationPresent(WriteOnly.class))
                    .collect(Collectors.toList()));
        }
        return list;
    }

    private static String getFieldName(String methodName) {
        return Introspector.decapitalize(methodName.substring(methodName.startsWith("is") ? 2 : 
                    methodName.startsWith("get") ? 3 : 0));
    }

}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章