web-dev-qa-db-ja.com

ジャージー:文字列のリストを返す

私は、Jerseyの文字列のリストをJSONおよびXMLとして返そうとしています。これは些細なことだと思いました。

私の最初の試みはこのようなものを書くことでした

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("/bar")
public List<String> get() {
    return dao.get();
}

そして、私はこれに似た出力を期待していました:["string1"、...、 "stringN]残念ながら私はこれを得ました:

com.Sun.jersey.api.MessageException: A message body writer for Java class Java.util.LinkedList, and Java type Java.util.List<Java.lang.String>, and MIME media type application/json was not found 

次に、ListのラッパーStringListを作成しました

@XmlRootElement
public class StringList {

    private List<String> data;

    public StringList() {
    }

    public StringList(List<String> data) {
        this.data = data;
    }

    public List<String> getData() {
        return data;
    }

    public void setData(List<String> data) {
        this.data = data;
    }
}

ファサードを

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("/foo")
public StringList stringlist() {
    return new StringList(sl());
}

これは、1を超えるアイテムを持つリストに最適です。

{"data":["foo","bar"]}

残念ながら、1つまたは0つの要素に対して2つの予期しない結果が得られます

{"data": "just one"} // for one element i would expect {"data": ["just one"]}

null // for no elements i would expect {"data": []}

私は完全に間違っていることをしていますか?どうすれば修正できますか?

17
user524824

javax.ws.rs.core.GenericEntity

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("/foo")
public GenericEntity<List<String>> stringlist()
{
  List<String> list = Arrays.asList("test", "as");

  return new GenericEntity<List<String>>(list) {};
}
6
sdorra

さて、サンプルを検索して修正できます

これは機能しますが、JSONにのみ使用でき、XMLには使用できません

@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/get")
public JSONArray get() {;
    return new JSONArray(dao.getStringList());
}

問題を修正しますが、一般的なアプローチもありますか?

8
user524824

Jerseyに希望どおりにリストを出力するように説得するには、独自のContextResolverを提供する必要があります。

@Provider
public class JaxbContentResolver implements ContextResolver<JAXBContext> {

    private Log log = LogFactory.getLog(getClass());
    private JAXBContext context;

    public JaxbContentResolver() throws JAXBException {
        Class[] types = {StringList.class};
        context = new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(true).arrays("data").build(), types);
    }

    @Override
    public JAXBContext getContext(Class<?> objectType) {
        log.trace("Entering Test-getContext for type: " + objectType.getSimpleName());
        return context;
    }
}

この方法のリストは、希望どおりに表示されます。

注:このアプローチの欠点の1つは、コードで1つの追加の場所を維持する必要があることです。別の(リストラッパー)クラスをRESTインターフェイスに追加する場合は、上記のコードに移動して、そのクラスをContextResolverに追加することを忘れないでください...

1
Julius Blank

提供された回答に加えて、MessageBodyWriter not found、次のような依存関係を追加してみてください:

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
    </dependency>
0
Skylar Saveland

これに対する私の解決策はラッパークラスでした(どこかで見つけました)。現在は機能しています。ルート要素としてjavas Listクラスをサポートしないことの背後にある考えを理解していません。多分それは私が知らないjson仕様/ベストプラクティスに関係しています。

しかし今のところこれを使用しています:

public class Houses {
    private List<String> houses;

    // Needed for jersey
    public Houses() { }

    public Houses(List<String> houses) {
        this.houses = houses;
    }

    public void setHouses(List<String> houses) {
        this.houses = houses;
    }

    public List<String> getHouses() {
        return this.houses;
    }
}
0
sigi

代替のJSON設定JSONConfiguration.natural()を使用する必要があります。

その代替構成をプロバイダーとして使用して独自のContextResolverを作成し、それが担当するクラスを通知するのが最善です。

代替構成をグローバルに別の方法で使用する方法を知りません。

0
someone