Весна монго писать только поле - PullRequest
3 голосов
/ 21 октября 2019

У меня есть абстрактный класс, описывающий монго-документ. Могут быть разные реализации этого класса, которые должны переопределять абстрактный метод. Вот упрощенный пример:

@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. Он пытается найти установщик для этого поля, но я не хочу определять установщик для него - метод может возвращать вычисленное значение, и не должно быть возможности его изменить. Хотя пустой установщик мог бы помочь, это больше похоже на обходной путь, и я бы постарался избежать этого.

Так что мне интересно, есть ли способ пропустить это конкретное свойство при чтении из БД? Что-то противоположное аннотации @Transient. Или аналогично @JsonIgnore в библиотеке Джексона.

Ответы [ 3 ]

1 голос
/ 25 октября 2019

Проблема в вашем случае заключается в названии метода со словом «get».

Имея слово «get», Spring думает, что есть атрибут с именем «что-то», и с этимон проверяет, есть ли у него соответствующий метод получения и установки.

Переименуйте ваш метод из «getSomething», например, в «selectedInformation».

1 голос
/ 21 октября 2019

Вы можете попробовать добавить свойство @Transient, чтобы оно игнорировалось при отображении полей. См. этот вопрос.

С другой стороны, если свойство просто игнорируется при чтении, вы можете указать пустой метод setter. Это позволит избежать exception of no accessor method.

. Или создать пользовательскую аннотацию и поместить все свойства, для которых должен быть пустой метод установки, в отдельный класс и аннотировать класс новой аннотацией. Этот класс может быть расширен при необходимости. Вы можете посмотреть на проект lombok , чтобы увидеть, как они создавали аннотации для методов получения и установки.

0 голосов
/ 01 ноября 2019

Удивительно, но не существует простого решения сделать только запись в поле.

Хотя создание пустого установщика решило бы проблему, я чувствую, что это нарушает принцип наименьшего удивления : если у вас есть установщик, вы ожидаете, что он установит значение.

Поэтому я решил создать собственную аннотацию @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));
    }

}
...