Quartz JobDataMap doesn't work for not-primitive types

大兔子大兔子 提交于 2019-12-22 10:54:58

问题


I have a following problem with Quartz JobDataMap. I expect that when using simple Quartz Job and passing not-primitive object (e.g. instance of StringBuilder) into JobDateMap, method execute (from my job) should be always invoked with different copy of objected I put. Unfortunately I always get instance of object I put into JobDateMap (like it would be a StatefulJob).

In bellow example I expect to get single '*' in every invocation while I get one more '*' every time.

public class MyJob implements Job {

    public static void main(String[] args) throws SchedulerException {

        SchedulerFactory schedFact = new StdSchedulerFactory();
        Scheduler sched = schedFact.getScheduler();

        JobDetail jobDetail = new JobDetail("job", Scheduler.DEFAULT_GROUP, MyJob.class);
        jobDetail.getJobDataMap().put("param", new StringBuilder());

        Trigger trigger = TriggerUtils.makeImmediateTrigger("trigger", 10, 100);
        trigger.setGroup(Scheduler.DEFAULT_GROUP);

        sched.scheduleJob(jobDetail, trigger);
        sched.start();

        try {
            Thread.sleep(1000L);
        } catch (Exception e) {}

        sched.shutdown(true);

    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        StringBuilder sb = (StringBuilder) context.getMergedJobDataMap().get("param");
        sb.append("*");
        System.out.println(sb.toString());

    }
}

I think, I'm missing something about how Quartz is working. Anybody knows what?


回答1:


"Only store primitive data types (including Strings) in JobDataMap to avoid data serialization issues short and long-term."

source: http://quartz-scheduler.org/documentation/best-practices




回答2:


There are other facilities in Quartz that allow you to pass non-primitives in a more optimized fashion. Check out SchedulerContext class functionality.

using System;
using System.Text;
using Quartz;
using Quartz.Impl;

namespace QuartzNET.Samples
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create RAMJobStore instance
            DirectSchedulerFactory.Instance.CreateVolatileScheduler(1);
            ISchedulerFactory factory = DirectSchedulerFactory.Instance;

            // Get scheduler and add object
            IScheduler scheduler = factory.GetScheduler();
            scheduler.Context.Add("History", new StringBuilder("Runtime History: "));

            // Create job and trigger
            IJobDetail job = JobBuilder.Create<MyJob>()
                                       .WithIdentity("MyJob")
                                       .Build();
            ITrigger trigger = TriggerBuilder.Create()
                                             .WithIdentity("Trigger")
                                             .StartNow()
                                             .WithSimpleSchedule(x => x
                                                .WithInterval(TimeSpan.FromMinutes(1))
                                                .RepeatForever())
                                             .Build();

            // Run it all
            scheduler.Start();
            scheduler.ScheduleJob(job, trigger);
        }
    }

    class MyJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            var history = context.Scheduler.Context["History"] as StringBuilder;
            history.AppendLine(context.NextFireTimeUtc.ToString());
            Console.WriteLine(context.NextFireTimeUtc);
        }
    }
}



回答3:


I used JSON to send complex objects to job. It's not very smart but works for my pursposes.

In your application:

jobDetail.getJobDataMap().put("YOUR_PARAM_NAME", yourObject.toJson());

In your job:

JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jsonObject = dataMap.getString("YOUR_PARAM_NAME");
YourClass yourObject = YourClass.fromJson(jsonObject);



回答4:


As per Best Practices of JobDataMap, we should not put complex objects in JobDataMap to avoid short term or long term issues. (There might be issues of serialization which of course will not be solved by modifying Complex object class to implement Serializable.)

Workaround: Pass complex objects as a Json String and deserialize them after retrieving it from JobDataMap.

For example,

class OrderLine {
        private long orderLineId;
        private Item item;
    }
    class Item {
        private long itemId;
        private String itemName;
   }
//Putting OrderLine object in JobDataMap
    jobDetail.getJobDataMap().put("complexData", new Gson().toJson(new OrderLine()));
// Retrieving data from JobDataMap
    String complexDataString = 
        context.getJobDetail().getJobDataMap().getString("complexData");
    OrderLine orderLine = new Gson().fromJson(complexDataString, OrderLine.class);



回答5:


I was hitting the same error in our project, but realized that I had a different setting that was blocking it. You can use non "property-related" objects, if you configure it. You're looking for this value in the config file for quartz settings.

<add key="quartz.jobStore.useProperties" value="false" />

False allows you to use other objects other than just properties. Once I changed this ( mine was true ), then it started working for me.



来源:https://stackoverflow.com/questions/14562379/quartz-jobdatamap-doesnt-work-for-not-primitive-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!