Как создать расписание на основе календаря с помощью jberet-ui?
Я использую jberet-ui (созданный из основной ветки https://github.com/jberet/jberet-ui.git), встроенный в затененную войну с jberet-rest-api, jberet-rest-common, jberet-schedule-executor и jberet-schedule-timer версии 1.4.0.Final в качестве зависимостей.
Когда я пытаюсь создать расписание на основе календаря, я получаю ответ 400 от api с сообщением "Не удалось запланировать выполнение задания для задания: ag-insurance-import-lisa-subscriptions". отображается внизу страницы, а текст
Unrecognized field "hour" (class javax.ejb.ScheduleExpression), not marked as ignorable
в теле ответа.
Как предполагается десериализовать это javax.ejb.ScheduleExpression? Это не похоже на простое pojo, которое можно просто привязать к модели json, и я не смог найти десериализатор в проектах jberet-rest*. Должен ли я предоставить свои собственные сериализаторы json (de)?
2 ответа
Существует образец пакетного приложения (scheduleTimer) с jberet-ui, и вы можете попробовать его.
Я никогда раньше не видел такой ошибки. Это может быть связано с некоторыми изменениями в разных версиях библиотеки Джексона (используется для привязки json). Вы можете попробовать точную версию зависимостей jackson-*, которая используется в приведенном выше примере проекта jberet.
Рассматриваемая строка кода находится в классе JobScheduleConfig.
Можете ли вы поделиться подробностями об ошибках и трассировкой стека из журнала WildFly server.log?
Чтобы обойти эту проблему, в настоящее время работает следующее.
военные зависимости:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jberet</groupId>
<artifactId>jberet-rest-commons</artifactId>
<version>1.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.jberet</groupId>
<artifactId>jberet-schedule-executor</artifactId>
<version>1.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.jberet</groupId>
<artifactId>jberet-schedule-timer</artifactId>
<version>1.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.jberet</groupId>
<artifactId>jberet-rest-api</artifactId>
<version>1.4.0.Final</version>
</dependency>
Затем создайте десериализатор json:
public class ScheduleExpressionDeserializer extends JsonDeserializer<ScheduleExpression> {
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE;
@Override
public ScheduleExpression deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
ScheduleExpression scheduleExpression = new ScheduleExpression();
// Payload example:
// {"year":"1","month":"2","dayOfMonth":"3","dayOfWeek":"4",
// "hour":"5","minute":"6","start":"2020-05-04T08:10:00.000Z",
// "end":"2020-06-05T08:12:00.000Z","timezone":"Africa/Blantyre"}
TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
Optional.ofNullable(treeNode.get("year"))
.flatMap(this::parseIntegerNode)
.ifPresent(scheduleExpression::year);
Optional.ofNullable(treeNode.get("month"))
.flatMap(this::parseIntegerNode)
.ifPresent(scheduleExpression::month);
Optional.ofNullable(treeNode.get("dayOfMonth"))
.flatMap(this::parseIntegerNode)
.ifPresent(scheduleExpression::dayOfMonth);
Optional.ofNullable(treeNode.get("dayOfWeek"))
.flatMap(this::parseIntegerNode)
.ifPresent(scheduleExpression::dayOfWeek);
Optional.ofNullable(treeNode.get("hour"))
.flatMap(this::parseIntegerNode)
.ifPresent(scheduleExpression::hour);
Optional.ofNullable(treeNode.get("minute"))
.flatMap(this::parseIntegerNode)
.ifPresent(scheduleExpression::minute);
Optional.ofNullable(treeNode.get("start"))
.flatMap(this::parseDateTimeNode)
.ifPresent(scheduleExpression::start);
Optional.ofNullable(treeNode.get("end"))
.flatMap(this::parseDateTimeNode)
.ifPresent(scheduleExpression::end);
Optional.ofNullable(treeNode.get("timezone"))
.map(TreeNode::asToken)
.map(JsonToken::asString)
.ifPresent(scheduleExpression::timezone);
return scheduleExpression;
}
private Optional<Integer> parseIntegerNode(TreeNode node) {
if (node instanceof TextNode) {
TextNode textNode = (TextNode) node;
return Optional.of(textNode)
.map(TextNode::asInt);
} else {
return Optional.empty();
}
}
private Optional<Date> parseDateTimeNode(TreeNode node) {
if (node instanceof TextNode) {
TextNode textNode = (TextNode) node;
return Optional.of(textNode)
.map(TextNode::asText)
.map(s -> OffsetDateTime.parse(s, dateTimeFormatter))
.map(OffsetDateTime::toInstant)
.map(Date::from);
} else {
return Optional.empty();
}
}
}
И используйте его в ObjectMapper, предоставляемом jax-rs:
@Provider
public class JacksonMapperResolver implements ContextResolver<ObjectMapper> {
@Override
public ObjectMapper getContext(Class<?> type) {
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("Custom deserializers");
simpleModule.addDeserializer(ScheduleExpression.class, new ScheduleExpressionDeserializer());
mapper.registerModule(simpleModule);
return mapper;
}
}