Возврат нескольких предметов из весенней партии ItemProcessor

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

@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 Batch, чтобы избежать списков в процессоре?

Обновить

Я открыл вопрос о весне Jira для этой проблемы.

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

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

3 ответа

Обработчик элементов принимает одну вещь и возвращает список

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);
        }
    }
}

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

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

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

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

public class Intializer {

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

И в вашем элементе Processor

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();
}

}
Другие вопросы по тегам