1

Jersey と Eclipselink MOXy を使用する比較的単純な RESTful Web サービスがあります。

データが XML としてフォーマットされている場合はサービスにリクエストを POST できますが、代わりに JSON として送信すると、サーバーは HTTP 400 (Bad Request) を生成し、「クライアントから送信されたリクエストは構文的に正しくありません。 "。

サービス側は次のようになります。

@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Subscription post(Subscription Subscription) {
    return Subscriptions.addSubscription(Subscription);
}

このような Web ページで Javascript から XML データを送信する場合、問題はありません。

 $.ajax({
    url: 'http://localhost:8080/MyService/subscription',
type: 'POST',
    data:  "<subscription><notificationType>EMAIL</notificationType><notificationAddress>test@example.com</notificationAddress></subscription>",
    headers: { 
            Accept : "application/xml",
            "Content-Type": "application/xml"
    },
     // .. other params ... 
 );

ただし、同等の JSON を使用すると、HTTP 400 - Bad Request が発生します。

 $.ajax({
    url: 'http://localhost:8080/MyService/subscription',
type: 'POST',
    data:  JSON.stringify(
                {subscription:{notificationType:"EMAIL",notificationAddress:"test@example.com"}}
            ),
    dataType: 'json'
    headers: { 
            Accept : "application/json",
            "Content-Type": "application/json"
     }
     // .. other params ... 
 );

Fiddler を使用してリクエストを調べたところ、データのフォーマットとヘッダーはすべて正しいように見えます。

興味深いことに、このコードにプラグインすると、まったく同じ JSON 文字列を正常にアンマーシャルできます。

String json = "{\"subscription\":{\"notificationType\":\"EMAIL\",\"notificationAddress\":\"test@example.com\"}}";
JAXBContext context = JAXBContext.newInstance(Subscription.class);
Unmarshaller m = context.createUnmarshaller();
m.setProperty("eclipselink.media-type", "application/json");
StringReader sr = new StringReader(json);
Subscription sub = (Subscription)m.unmarshal(sr);
System.out.println(sub.toString());

サブスクリプション クラスは次のように定義されます。

@XmlRootElement(name="subscription")
public class Subscription {

    public enum NotificationType { EMAIL, SMS };

    private String notificationAddress;

    private NotificationType notificationType;

    public String getNotificationAddress() {
        return notificationAddress;
    }

    public void setNotificationAddress(String notificationAddress) {
        this.notificationAddress = notificationAddress;
    }
    public NotificationType getNotificationType() {
        return notificationType;
    }

    public void setNotificationType(NotificationType notificationType) {
        this.notificationType = notificationType;
    }
    public Subscription() {
    }

    @Override
    public String toString() {
        String s = "Subscription";
        if (getNotificationAddress() != null) {
            s += "(" + getNotificationType().toString() + ":" + getNotificationAddress() + ")";
        }
        return s;
    }
}

サブスクライバー クラスを含むパッケージの jaxb.properties に次の行を追加して、Eclipselink MOXy を JAXB プロバイダーとして構成しました。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

そして、少なくともサービスから出て行くオブジェクトをマーシャリングするために、それはうまくいくようです。

私は何が欠けていますか?

編集: これは、JSON データを投稿するときに Fiddler がキャプチャするものです。

POST http://localhost:8080/MyService/subscription HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 86
Accept: application/json
Origin: http://localhost:8080
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36
Content-Type: application/json
Referer: http://localhost:8080/TestPage/AddSubscription.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

{"subscription":{"notificationType":"EMAIL","notificationAddress":"test@example.com"}}

アップデート:

以下のブレイズの回答からオプション#2を取得し、アプリケーション派生クラスを作成しました。

import java.util.*;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;

public class MyApplication  extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> set = new HashSet<Class<?>>(2);
        set.add(MOXyJsonProvider.class);
        set.add(SubscriptionResource.class); // the class containing my @POST service method.
        return set;
    }
 }

そして web.xml に追加:

   <param-name>javax.ws.rs.Application</param-name>
   <param-value>com.example.MyApplication</param-value> 

そして今、HTTP 400 を取得せず、サービスのコードがヒットしましたが、これは以前にはありませんでしたが、渡されたサブスクリプション オブジェクトには初期化されていないフィールドがすべて含まれています。たとえば、notificationAddress は null です。XML を使用して投稿すると、問題なく動作します。

更新#2:

問題を示す最小のサブセットにコードを縮小しました。ここで取得できます。

https://www.dropbox.com/sh/2a6iqw65ey0ahrk/D2ILi_722z

上記のリンクには、2 つの Eclipse プロジェクトを含む .zip が含まれています。TestService (Subscription オブジェクトを受け入れる Jersey RESTful サービス) と TestPage (JSON または XML でサブスクリプション オブジェクトを POST するための JavaScript を含む .html ページ)。

サービスのポスト メソッドにブレークポイントを配置し、テスト ページを使用して JSON 要求を送信すると、初期化されていないサブスクリプション オブジェクトが渡されることがわかります。

4

1 に答える 1