0

Quartz スケジューラーの上に REST API サーバーを作成しようとしています。org.quartz.Trigger および org.quartz.JobDetail オブジェクトを JSON として返せるようにしたいと考えています。問題は、jar を再コンパイルせずに @XmlRootElement をこれらのクラスに追加できないことです。これにより、将来のアップグレードなどで問題が発生します。テストしたところ、@XmlRootElement を追加するときにクラスのリストをシリアル化できましたが、 「Java クラス java.util.ArrayList、Java タイプ java.util.List、および MIME メディア タイプ application/json のメッセージ ボディ ライターが見つかりませんでした」というエラーが表示されます。カスタム MessageBodyWriter を追加しようとしましたが、それでも問題は解決しないようです。@XmlRootElement を追加するために Quartz コードを変更することなく、Quartz クラスを JSON にマーシャリングする方法はありますか。

@Path("/jobs")
public class JobsResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Trigger> listScheduledJobs() throws SchedulerException {
        return TaskEngine.getInstance().listScheduledJobs();
    }

}

Web サーバー構成

public class TaskEngineWebServer {

    private static final Logger logger = Logger.getLogger(TaskEngineWebServer.class.getName());

    private Server server;

    public TaskEngineWebServer() {
        this(8585);
    }

    public TaskEngineWebServer(Integer port) {
        server = new Server(port);

        logger.info("Configuring rest service to start at url /r");
        ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.NO_SECURITY);
        //handler.getInitParams().put("com.sun.jersey.api.json.POJOMappingFeature", "true");
        PackagesResourceConfig packagesResourceConfig = new PackagesResourceConfig("com.hp.vf.scheduler.server.rest");

        ServletContainer servletContainer = new ServletContainer(packagesResourceConfig);
        handler.addServlet(new ServletHolder(servletContainer), "/r/*");

        server.setHandler(handler);
        logger.info("Done configuring rest service");
    }

    public void start() throws Exception {
        server.start();
    }

    public void stop() throws Exception {
        server.stop();
    }

    public boolean isStarted() {
        return server.isStarted();
    }

    public boolean isStopped() {
        return server.isStopped();
    }
}
4

2 に答える 2

1

List を JSON として直接返すことはできないと思います。このリストを含むラッパー クラスが必要です。たとえば、このようなことを試してください

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class TriggerWrapper{

  private List<Triggers> triggers;

  public List<Triggers> getTriggers(){
   if(triggers==null){
     triggers = new ArrayList<Triggers>();
   }
   return triggers;
  }
}

次に、残りのサービスクラスで:

@Path("/jobs")
public class JobsResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public TriggerWrapper listScheduledJobs() throws SchedulerException {
        TriggerWrapper response = new TriggerWrapper();
        List<Triggers> triggers =  TaskEngine.getInstance().listScheduledJobs();
        response.getTriggers.addAll(triggers);
        return response;
    }

}

あなたのjsonは次のようになります:

{
    "triggerwrapper": {
        "triggers": [
            {
                "triggerid": 1
            },
            {
                "triggerid": 2
            }
        ]
    }
}

もちろん、必要に応じて、json から root 要素タグをドロップして、jersey で構成可能にすることもできます。

于 2012-12-05T06:09:09.033 に答える
1

私はついにきれいな解決策を見つけました。それには、独自の MediaBodyWriter クラスを作成し、それをプロバイダーとして追加することが含まれます。デフォルトのjaxb to jsonプロバイダーがあなたのものをオーバーライドするため、jersey-bundle jarを使用していないことを確認する必要があります。

必要な瓶

ジャージ-コア ジャージ-サーブレット ジャージ-サーバー

ジャクソン-注釈 ジャクソン-データバインド ジャクソン-コア

この MediaWriter の例を Web のどこかで見つけました。URLがなくて申し訳ありませんが、書いてくれた人に感謝します。

@Provider
@Produces({ MediaType.APPLICATION_JSON })
public class JacksonWriter implements MessageBodyWriter<Object> {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Override
    public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public long getSize(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
            OutputStream entityStream) {
        try {
            MAPPER.writeValue(entityStream, value);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

ロードすると、プロバイダーがロードされたことを示すログ メッセージが表示されます。

これにより、JAXB アノテーションに依存せず、単にオブジェクト マッパー/リフレクションを使用するため、期待していた json 出力が得られました。おそらく効率が悪いですが、私の場合は問題ありません。

于 2012-12-05T16:23:17.287 に答える