[
https://issues.apache.org/jira/browse/CXF-1928?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Pedro Ballesteros updated CXF-1928:
-----------------------------------
Estimated Complexity: Novice (was: Unknown)
Description:
When you use JSONProvider your services only can work with Content-Type
"application/json". If you configure another Content-Type in your services,
JSONProvicer doesn't process the request and doesn't do XML-JSON
transformations.
I know it isn't right to use another Content-Type with JSON Responses, but I
think it should be developer decision.
You might need to use "text/plain", "text/json", even if it isn't completely
right. For example, I'm doing a public REST API, and I'd like it to be robust
and support several Content-Types, like "json/text", "json/application",
"text/plain".
But JSON Provider only works with "json/application".
The problem is JSONProvider "@Produce" and "@Consumes" annotations:
@Produces("application/json")
@Consumes("application/json")
@Provider
public final class JSONProvider extends AbstractJAXBProvider { ... }
And you can't use inheritance to override class Annotations because
JSONProvider class is final.
I think it should be this way:
@Produces("*/*")
@Consumes("*/*")
@Provider
public final class JSONProvider extends AbstractJAXBProvider { ... }
This way developers can choose "@Produces" and "@Consumers" annotation service
Beans.
Ej:
When you don't use JSONProvider the behavior is like this:
@GET
@ProduceMime("text/plain" )
public ContactEntry get() { ... }
It produces XML if you are using JAXB. (It isn't probably good thing to
response XML as text/plain content type, I know, but the important thing is
that I can.
@GET
@ProduceMime("text/xml" )
public ContactEntry get() { ... }
It produces XML too. (That's better, to use XML with text/xml content type).
So you can choose the content type when you aren't using JSONProvider, even if
you are using wrong content types.
But if you use JSONProvider:
<bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider"/>
<jaxrs:server id="contactsRemoteService" address="/">
<jaxrs:serviceBeans>
<ref bean="contactsService" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
With:
@GET
@ProduceMime("text/plain" )
public ContactEntry get() { ... }
or
@GET
@ProduceMime("text/json" )
public ContactEntry get() { ... }
The service produces XML, even though you are using the JSONProvider, but:
@GET
@ProduceMime("json/application" )
public ContactEntry get() { ... }
It produces JSON.
But you probably might need to configure your service with several
content-types, like "text/json", "json/application", etc. But you can't with
JSONProvider. And it is a final class, so you can't override Annotations with
inheritance.
So if you use this:
@GET
@ProduceMime({"text/json", "json/application"})
@ConsumeMime({"text/json", "json/application"})
public ContactEntry get() { ... }
The bean response JSON with json/application content types, but XML with
text/json content-type.
You can use a delegation design pattern (I suppose there are better solutions):
See attach file.
Best Regards,
Pedro
was:
When you use JSONProvider your services only can work with MIME
"application/json". If you configure another MIME in your service, JSONProvicer
doesn't process the request and doesn't change XML into JSON.
I know it doesn't right not to use "application/json", but I think that should
be developer decision. Maybe I need to use "plain/text", "json/text", even if
it's wrong.
The problem is just JSONProvider Produces, Consumes declaration:
@Produces("application/json")
@Consumes("application/json")
@Provider
public final class JSONProvider extends AbstractJAXBProvider { ... }
And you can't override class Annotations because JSONProvider is final.
I think it should be this way:
@Produces("*/*")
@Consumes("*/*")
@Provider
public final class JSONProvider extends AbstractJAXBProvider { ... }
So that developers can choose Produces and Consumers they mean in Service Beans.
Ej:
When I don't use JSONProvider the behavior is like this:
@GET
@ProduceMime("text/plain" )
public ContactEntry get() { ... }
Produces XML because I'm using JAXB. (It isn't good using XML like plain text
content type, I know, but I can).
@GET
@ProduceMime("text/xml" )
public ContactEntry get() { ... }
Produces XML too. (That's better).
So I can choose the content type when I don't use JSONProvider, even if i'm
doing bad things.
But if I use JSONProvider:
<jaxrs:server id="contactsRemoteService" address="/">
<jaxrs:serviceBeans>
<ref bean="contactsService" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
<bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider"/>
With:
@GET
@ProduceMime("text/plain" )
public ContactEntry get() { ... }
or
@GET
@ProduceMime("text/json" )
public ContactEntry get() { ... }
My service produces XML, but with:
@GET
@ProduceMime("json/application" )
public ContactEntry get() { ... }
It produces JSON.
Maybe I'd like to configure my service like that, I can't. And as JSONProvider
is a final class, the only solution is delegation pattern:
This code is tested:
// JSON don't decides Content-Type
@ProduceMime("*/*")
@ConsumeMime("*/*")
@Provider
public class FreeMimeJSONProvider extends AbstractJAXBProvider {
private JSONProvider jsonProvider;
public void setJsonProvider(JSONProvider jsonProvider) {
this.jsonProvider = jsonProvider;
}
@Override
public void setSchemas(List<String> locations) {
jsonProvider.setSchemas(locations);
}
public void setNamespaceMap(Map<String, String> namespaceMap) {
jsonProvider.setNamespaceMap(namespaceMap);
}
public Object readFrom(Class<Object> type, Type genericType, Annotation[]
annotations, MediaType m,
MultivaluedMap<String, String> headers, InputStream is)
throws IOException {
return jsonProvider.readFrom(type, genericType, annotations, m,
headers, is);
}
public void writeTo(Object obj, Class<?> cls, Type genericType,
Annotation[] anns,
MediaType m, MultivaluedMap<String, Object> headers, OutputStream os)
throws IOException {
jsonProvider.writeTo(obj, cls, genericType, anns, m, headers, os);
}
}
So Content-Types are configured in service classes, as always:
@Path ("/")
public class ContactsService {
@GET
@ProduceMime("text/json" ) // I'm using JSONProvider but I wan't
"text/json" MIME
public ContactEntry get() {
....
}
}
And in Spring:
<jaxrs:server id="contactsRemoteService" address="/">
<jaxrs:serviceBeans>
<ref bean="contactsService" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
<!-- JSONProvider inside My Provider just to override Consumers Produces
Annotations -->
<bean id="jsonProvider" class="aa.aaaaa.aaaaa.FreeMimeJSONProvider">
<property name="jsonProvider">
<bean class="org.apache.cxf.jaxrs.provider.JSONProvider"/>
</property>
</bean>
<bean id="contactsService" class="aa.aaaaa.aaaaa.ContactsService" />
Best Regards,
Pedro
> You cannot change "@ProduceMime", "@ConsumeMime" or "@Producers", "@Consumer"
> in JSONProvider
> ---------------------------------------------------------------------------------------------
>
> Key: CXF-1928
> URL: https://issues.apache.org/jira/browse/CXF-1928
> Project: CXF
> Issue Type: Bug
> Components: REST
> Affects Versions: 2.1.3
> Environment: Tomcat 6.0.18, Spring 2.5
> Reporter: Pedro Ballesteros
>
> When you use JSONProvider your services only can work with Content-Type
> "application/json". If you configure another Content-Type in your services,
> JSONProvicer doesn't process the request and doesn't do XML-JSON
> transformations.
> I know it isn't right to use another Content-Type with JSON Responses, but I
> think it should be developer decision.
> You might need to use "text/plain", "text/json", even if it isn't completely
> right. For example, I'm doing a public REST API, and I'd like it to be
> robust and support several Content-Types, like "json/text",
> "json/application", "text/plain".
> But JSON Provider only works with "json/application".
> The problem is JSONProvider "@Produce" and "@Consumes" annotations:
> @Produces("application/json")
> @Consumes("application/json")
> @Provider
> public final class JSONProvider extends AbstractJAXBProvider { ... }
> And you can't use inheritance to override class Annotations because
> JSONProvider class is final.
> I think it should be this way:
> @Produces("*/*")
> @Consumes("*/*")
> @Provider
> public final class JSONProvider extends AbstractJAXBProvider { ... }
> This way developers can choose "@Produces" and "@Consumers" annotation
> service Beans.
> Ej:
> When you don't use JSONProvider the behavior is like this:
> @GET
> @ProduceMime("text/plain" )
> public ContactEntry get() { ... }
> It produces XML if you are using JAXB. (It isn't probably good thing to
> response XML as text/plain content type, I know, but the important thing is
> that I can.
> @GET
> @ProduceMime("text/xml" )
> public ContactEntry get() { ... }
> It produces XML too. (That's better, to use XML with text/xml content type).
> So you can choose the content type when you aren't using JSONProvider, even
> if you are using wrong content types.
> But if you use JSONProvider:
> <bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.JSONProvider"/>
> <jaxrs:server id="contactsRemoteService" address="/">
> <jaxrs:serviceBeans>
> <ref bean="contactsService" />
> </jaxrs:serviceBeans>
> <jaxrs:providers>
> <ref bean="jsonProvider" />
> </jaxrs:providers>
> </jaxrs:server>
> With:
> @GET
> @ProduceMime("text/plain" )
> public ContactEntry get() { ... }
> or
> @GET
> @ProduceMime("text/json" )
> public ContactEntry get() { ... }
> The service produces XML, even though you are using the JSONProvider, but:
> @GET
> @ProduceMime("json/application" )
> public ContactEntry get() { ... }
> It produces JSON.
> But you probably might need to configure your service with several
> content-types, like "text/json", "json/application", etc. But you can't with
> JSONProvider. And it is a final class, so you can't override Annotations with
> inheritance.
> So if you use this:
> @GET
> @ProduceMime({"text/json", "json/application"})
> @ConsumeMime({"text/json", "json/application"})
> public ContactEntry get() { ... }
> The bean response JSON with json/application content types, but XML with
> text/json content-type.
> You can use a delegation design pattern (I suppose there are better
> solutions): See attach file.
> Best Regards,
> Pedro
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.