Возврат нескольких предметов из весенней партии 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();
}
}