Reputation: 1801
Im using jberet-ui (built from master branch of https://github.com/jberet/jberet-ui.git) embedded in a shaded war with jberet-rest-api, jberet-rest-common, jberet-schedule-executor and jberet-schedule-timer version 1.4.0.Final as dependencies.
When I try to create a calendar-based schedule, I get a 400 response from the api with a message 'Failed to schedule job execution for job: ag-insurance-import-lisa-subscriptions.' displayed in the bottom of the page, and the text
Unrecognized field "hour" (class javax.ejb.ScheduleExpression), not marked as ignorable
in the response body.
How is this javax.ejb.ScheduleExpression supposed to be deserialized? It does not seem like a simple pojo that could be simply bound to a json model, and I couldn't find any deserializer in the jberet-rest* projects. Am I supposed to provide my own json (de)serializers?
Upvotes: 0
Views: 239
Reputation: 1801
To work around this issue, currently, the following works.
war dependencies:
<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>
Then create a json deserializer:
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();
}
}
}
And use it in a jax-rs-provided ObjectMapper:
@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;
}
}
Upvotes: 0
Reputation: 1138
There is a sample batch app (scheduleTimer) with jberet-ui, and you may want to check it out.
I've never seen this error before. It could be related to some changes across different jackson library versions (used for json binding). You may want to try the exact version of jackson-* dependencies as used in the above jberet sample project.
The line of code in question is in JobScheduleConfig class.
Can you share error details and stacktrace from WildFly server.log?
Upvotes: 0