Возвращает несколько элементов из spring партии ItemProcessor

Я пишу пакетное задание spring, и на одном из моих шагов у меня есть следующий код для процессора:

@Component
public class SubscriberProcessor implements ItemProcessor<NewsletterSubscriber, Account>, InitializingBean {

    @Autowired
    private AccountService service;

    @Override public Account process(NewsletterSubscriber item) throws Exception {
        if (!Strings.isNullOrEmpty(item.getId())) {
            return service.getAccount(item.getId());
        }
        // search with email address
        List<Account> accounts = service.findByEmail(item.getEmail());
        checkState(accounts.size() <= 1, "Found more than one account with email %s", item.getEmail());
        return accounts.isEmpty() ? null : accounts.get(0);
    }

    @Override public void afterPropertiesSet() throws Exception {
        Assert.notNull(service, "account service must be set");
    }
}

Вышеприведенный код работает, но я обнаружил, что есть некоторые случаи ребер, где допускается более одного Account за NewsletterSubscriber. Поэтому мне нужно удалить проверку состояния и передать более чем одному Account писателю элемента.

Одно из найденных решений - изменить как ItemProcessor, так и ItemWriter для работы с типом List<Account> вместо Account, но это имеет два недостатка:

  • Код и тесты более уродливы и сложнее писать и поддерживать из-за вложенных списков в писателя
  • Самое важное более одного объекта Account может быть записано в той же транзакции, потому что список, предоставленный писателю, может содержать несколько учетных записей, и я хотел бы избежать этого.

Есть ли способ, может быть, использовать прослушиватель или заменить какой-либо внутренний компонент, используемый пакетом spring, чтобы избежать списков в процессоре?

Update

Я открыл проблему на spring Jira для этой проблемы.

Я изучаю isComplete и getAdjustedOutputs методы в FaultTolerantChunkProcessor, которые помечены как точки расширения в SimpleChunkProcessor, чтобы увидеть, могу ли я каким-либо образом использовать их для достижения моей цели.

Любые подсказки приветствуются.

Ответ 1

Элемент Процессор принимает одну вещь и возвращает список

MyItemProcessor implements ItemProcessor<SingleThing,List<ExtractedThingFromSingleThing>> {
    public List<ExtractedThingFromSingleThing> process(SingleThing thing) {
    //parse and convert to list
    }
}

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

@StepScope
public class ItemListWriter<T> implements ItemWriter<List<T>> {
    private ItemWriter<T> wrapped;

    public ItemListWriter(ItemWriter<T> wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public void write(List<? extends List<T>> items) throws Exception {
        for (List<T> subList : items) {
            wrapped.write(subList);
        }
    }
}

Ответ 2

Невозможно вернуть более одного элемента для каждого звонка в пакет ItemProcessor в Spring, не попадая далеко в сорняки. Если вы действительно хотите узнать, где выходят отношения между ItemProcessor и ItemWriter (не рекомендуется), посмотрите на реализации интерфейса ChunkProcessor. В то время как простой случай (SimpleChunkProcessor) не так уж плох, если вы используете какую-либо отказоустойчивую логику (пропустите/повторите попытку через FaultTolerantChunkProcessor), она становится очень неудобно быстрой.

Более простой вариант заключается в том, чтобы переместить эту логику в ItemReader, которая делает это обогащение, прежде чем возвращать элемент. Обменивайте все ItemReader, которые вы используете в пользовательской реализации ItemReader, которая выполняет поиск службы перед возвратом элемента. В этом случае вместо возврата NewsletterSubscriber из читателя вы должны вернуть Account на основе предыдущей информации.

Ответ 3

Вместо возврата возвращаемой учетной записи создайте AccountWrapper или Collection. Писатель, очевидно, должен учитывать это:)

Ответ 4

Вы можете сделать трансформер для преобразования вашего Pojo (объект Pojo из файла) в вашу сущность, сделав следующий код:

public class Intializer {

public static LGInfo initializeEntity() throws Exception {
    Constructor<LGInfo> constr1 = LGInfo.class.getConstructor();
    LGInfo info = constr1.newInstance();
    return info;
}
}

И в вашем пункте Процессор

public class LgItemProcessor<LgBulkLine, LGInfo> implements ItemProcessor<LgBulkLine, LGInfo> {

private static final Log log = LogFactory.getLog(LgItemProcessor.class);

@SuppressWarnings("unchecked")
@Override
public LGInfo process(LgBulkLine item) throws Exception {
    log.info(item);
    return (LGInfo) Intializer.initializeEntity();
}

}