Arunas
Arunas

Reputation: 328

quartz jdbc serialize/deserialize object

I've got this problem where I can't deserialize object using quartz JobDataMap using JDBC. Same code using RAMJobStore works fine.

I simply created a basic class for testing

import java.io.Serializable;

public class Test implements Serializable {
    private static final long serialVersionUID = 1L;
    private String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }
}

Then in quartz

Test test = new Test();
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("test", test);

And in Quartz job

JobDataMap data = context.getMergedJobDataMap();    
Test test = (Test) data.get("test");

And the exception I get is this

java.lang.ClassCastException: com.venclovas.quartz.buildings.Test cannot be cast to com.venclovas.quartz.buildings.Test at com.venclovas.quartz.buildings.BuildingsUpgradeJob.execute(BuildingsUpgradeJob.java:39) at org.quartz.core.JobRunShell.run(JobRunShell.java:202) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)

When I debug the returned object - it looks perfectly fine to me (before casting)

DB definition

| QRTZ_TRIGGERS | CREATE TABLE `QRTZ_TRIGGERS` (
  `SCHED_NAME` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL,
  `TRIGGER_NAME` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `TRIGGER_GROUP` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `JOB_NAME` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `JOB_GROUP` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `DESCRIPTION` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
  `PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
  `PRIORITY` int(11) DEFAULT NULL,
  `TRIGGER_STATE` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
  `TRIGGER_TYPE` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  `START_TIME` bigint(13) NOT NULL,
  `END_TIME` bigint(13) DEFAULT NULL,
  `CALENDAR_NAME` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `MISFIRE_INSTR` smallint(2) DEFAULT NULL,
  `JOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
  KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |

Serialized object is stored as blob in JOB_DATA

Quartz documentation states that

The JobDataMap can be used to hold any amount of (serializable) data objects

http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-03.html

So my thinking goes that perhaps this is a problem with DB etc and not with quartz since RAMJobStore works fine? Any ideas?

I know that there are other ways to pass Objects to quartz job and they work e.g.

SCHEDULER.getContext().put("buildingsModel", buildingsModel);

But I am not going to run quartz with @DisallowConcurrentExecution which probably means I could get into trouble with concurrent jobs. Passing data via JobDataMap is probably a way to go (to be tested if I can get it working). Another solution would be to just pass primitive types, but again that would mean more load to mysql which I want to avoid.

Upvotes: 1

Views: 2877

Answers (1)

bob gabriels
bob gabriels

Reputation: 1

deserialization from hexstring : (with jobdata in the form of 0xACED00057 ... remove "0x")

ByteArrayInputStream bis = new ByteArrayInputStream(Hex.decodeHex(inputString));
ObjectInputStream ois = new ObjectInputStream(bis);
JobDataMap jobDataMap = (JobDataMap) ois.readObject();
Iterator keys = jobDataMap.keySet().iterator();
while (keys.hasNext()) {
    StringBuffer buf = new StringBuffer();
    String key = (String) keys.next();
    buf.append(key).append("=");
    Object value = jobDataMap.get(key);
    buf.append(value);
          /* output buf */
 }

Upvotes: 0

Related Questions