Как создать расписание на основе календаря с помощью 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;
    }
}
Другие вопросы по тегам