0

次のように構成された application/json を返す CXF REST サービスを作成しました。

プロスペクトジェネレーター:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("/consume")
public Prospect convertProspectToJson(Prospect prospect,@QueryParam("customerType") String customerType){

    //DTO logic goes here
    System.out.println("Prospect obj received.."+prospect.getProspectName());

    prospect.setCustomerType(customerType);

    return prospect;

}

このサービスは、JBoss Fuse にデプロイされると機能します。

これで、次のような Camel Route ビルダーができました。

public class ServiceRouter extends RouteBuilder {

/* (non-Javadoc)
 * @see org.apache.camel.builder.RouteBuilder#configure()
 */
@Override
public void configure() throws Exception {

    from("jetty://http://localhost:8182/route/prospect?bindingStyle=SimpleConsumer")
    //The Raw type to String conversion is done here. Refer the class for details
    //Processor converts the Message from byte[] to String
    .process(new ResponseToStringProcessor())
    .unmarshal("jsonDataformat") //jsonDataformat - bean in blueprint XML for converting to requested object type
    .to("cxfrs://http://localhost:8181/cxf/prospect/consume")
    /*1) The above line has the BodyType as Cxf's ResponseImpl instead of Prospect Object
    * 2) The below bean accepts type only as Prospect object and hence I get exception */
    .to("bean:prospectService?method=doSomething");

}

見込み客サービス:

public class ProspectService {
    public void doSomething(@Body Prospect prospect){

    System.out.println("Prospect Service got the request.."+prospect.getCustomerType());

    }
}

定義された Bean にルーティングしようとすると、次の例外が発生します。

org.apache.camel.InvalidPayloadException: タイプのボディはありません: com.karthik.bo.Prospect が値を持っています: タイプの org.apache.cxf.jaxrs.impl.ResponseImpl@54c96476

このエラーを解決するにはどうすればよいですか? ResponseImpl を POJO に変換する方法がわかりません。来たトレースは示します:

BodyType:org.apache.cxf.jaxrs.impl.ResponseImpl, Body:{"prospect":{"customerType":"VIP","prospectId":999,"prospectName":"karthik"}}

ResponseImpl を String (JSON ペイロードを含む) に変換しようとしましたが、常に IOException ストリームが閉じられます。-以下の変換コード:

public void convert(Exchange exchange){

InputStream is =  (InputStream)exchange.getIn().getBody(ResponseImpl.class).getEntity();

String s="";
try {
    s = org.apache.commons.io.IOUtils.toString(is);
    is.close();
} catch (IOException e) {
    e.printStackTrace();
}
System.out.println("in convertor..."+s);

}

多くの失敗の試み(コメントで言及)の後、最終的な解決策は次のように FallBackCoverter を作成することでした-これはストリームを閉じた IOException をスローしませんでした。

@FallbackConverter
    public static <T> T convertTo(Class<T> type, Exchange exchange, Object value, TypeConverterRegistry registry){

        System.out.println("Checking fall backconverter");
        if (ResponseImpl.class.isAssignableFrom(value.getClass())) {
            TypeConverter tc = registry.lookup(type, ResponseImpl.class);
            if (tc == null && type.getName().equals("com.karthik.bo.Prospect")) {
                Prospect prospect=new Prospect();
                try(InputStream is =  (InputStream)((ResponseImpl)value).getEntity()) {
                    if(is!=null){
                        String s = org.apache.commons.io.IOUtils.toString(is);
                        if(s!=null && s.length()>0){
                            ObjectMapper mapper = new ObjectMapper();
                            prospect = mapper.readValue(s, Prospect.class);

                        }
                        is.close();
                    }
                } catch (IOException e) {
                    System.out.println("Exception occured"+e.getMessage());
                }
                return type.cast(prospect);
            }
        }

        return (T) Void.TYPE;
    }

私のルーターは次のように変更されました:

from("jetty://http://localhost:8182/route/prospect?bindingStyle=SimpleConsumer")
        //The Raw type to String conversion is done here. Refer the class for details
        .process(new ResponseToStringProcessor())
        .unmarshal("jsonDataformat")
        .to("cxfrs://http://localhost:8181/cxf/prospect/consume")
        .convertBodyTo(Prospect.class)
        .to("bean:prospectService?method=doSomething")
        .marshal("jsonDataformat");

これが唯一の方法であるかどうかを確認せずに、これを解決策としてマークすることはできませんでした. camel-cxf で古い JIRA の問題を見つけた後、私のソリューションが実装されました

https://issues.apache.org/jira/browse/CAMEL-3208

この目的のために FallBackConvertor を作成する必要がありました。

4

1 に答える 1

1

サービス クラスのリフレクションを介して通話が受信されていないようです。変換クラスが何をしようとしているのか正確にはわかりませんが、クライアント/サーバーの最後にプロバイダーを追加して、Json から POJO へのマッピングを処理しようとしましたか? 私にとってうまくいった簡単な例を投稿させてください (これは設計図で行いましたが、DSL でも同様に機能するはずです)。コードの状態で申し訳ありませんが、機能するものと機能しないものを見つけるために、まだ多くのテストを行っています。

ここに、cxf rs クライアントとサーバーの両方があります。

<cxf:rsClient id="rsClient" address="${CXFclient}" serviceClass="com.limelight.esb.servicedb.services.ServiceDBExternalRestService"
    loggingFeatureEnabled="true" loggingSizeLimit="500">
    <cxf:providers>
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
    </cxf:providers>
</cxf:rsClient>

<cxf:rsServer id="rsServer" address="${CXFserver}${serverService}" serviceClass="com.limelight.esb.servicedb.services.ServiceDBRestService"
    loggingFeatureEnabled="true" loggingSizeLimit="500">
    <cxf:providers>
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />
    </cxf:providers>
</cxf:rsServer>

私のルートは次のようになります。

    <route id="servicedb.rest.company.get.route">
        <from uri="{{servicedb.rest.company.get}}" />
        <log message="Rest getCompany called." />
        <to uri="{{servicedb.company.get}}" />
        <removeHeader headerName="Content-Length" />
    </route>

そして最後に私のサービスクラス:

@Path("/servicedb/")
public class ServiceDBRestService {
    @GET
    @Path("company/{id}")
    @Produces("application/json")
    public ServiceDBCompanyResponse getCompanyRest(@PathParam("id") String id) {
        //just an interface
        return null;
    }
}

これは、予期される応答オブジェクトのヘッダーに関連している可能性もあります。そのためには、カスタム プリプロセッサを使用してそれを変更し、呼び出しを行う前にそれをルートに追加するだけです。

public class ServiceDBProcessors implements Processor {

@Override
public void process(Exchange exchng) throws Exception {        
    exchng.getIn().setHeader("CamelCxfRsResponseClass", your.class.here.class);
}

さて、私がこのアイテムに出くわした理由は、soap を介して電話をかけたときにこの問題に遭遇したためです。上記が役に立たない場合は、少なくとも変換を少し削除する、もう少し良い答えを提供できます。リターンの後に別のハンドラーを配置して変換を行うことができ、入力パラメーターが文字列の場合はリフレクションで取得する必要があることがわかりました。次のようなクラスを作成する必要がありました。

    public ServiceDBCompany convertCompany(String companyResponseBody) {
        ServiceDBCompany newCompany = new ServiceDBCompany();
        if(companyResponseBody!=null && companyResponseBody.length()>0){
            ObjectMapper mapper = new ObjectMapper();
            try {
                ServiceDBCompanyResponse company = mapper.readValue(companyResponseBody, ServiceDBCompanyResponse.class);
                newCompany.setCompanyId(company.getCompanyId());
                newCompany.setName(company.getCompanyName());
            } catch(IOException e) {
                System.out.println("Exception reading body, returning null " + ServiceDBCompany.class);
            }
        }
        return newCompany;
}

これにより、少なくとも試してみることができるソリューションのいくつかのアイデアが得られることを願っています!

于 2015-05-13T17:43:45.167 に答える