Our problem is, our service GET /services/v1/myobject returns object named Xyz. This representation is used by multiple existing clients.
The new service GET /services/v2/myobject needs to expose exact same object but with different name, say XyzLmn
Now one obvious solution would be to create two classes Xyz and XyzLmn, then copy Xyz into XyzLmn and expose XyzLmn in the v2.
What I am looking for is, how can I keep the same java pojo class Xyz and conditionally serialize it to either XyzLmn or Xyz ?
have you try to add the #JsonIgnoreProperties(ignoreUnknown = true) on your domain object?
One solution is:
Write a customer serializer that emits XyzLmn
Register the customer serializer conditionally
public class XyzWrapperSerializer extends StdSerializer<Item> {
public ItemSerializer() {
this(null);
}
public ItemSerializer(Class<Item> t) {
super(t);
}
#Override
public void serialize(
Item value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("XyzLmn", value.id);
jgen.writeEndObject();
} }
XyzWrapper myItem = new XyzWrapper(1, "theItem", new User(2, "theUser"));
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(XyzWrapper.class, new XyzWrapperSerializer());
mapper.registerModule(module);
String serialized = mapper.writeValueAsString(myItem);
Related
I'm using Spring MVC 4.3.2 with #RestController and I would like to be able to dynamically filter JSON properties specified by our clients in the request.
To keep things easy, let's say I have a Person POJO that contains firstName and lastName fields. This POJO is generated, that's why you will see that I'm using a mixin.
Let's say one client want to retrieve all the persons' firstName, he will call our rest endpoint like this : http://localhost/persons&fields=firstName. And the json will only contains the firstName, not the lastName fields.
Here is my Controller:
#RestController
public class RestPersonController implements PersonApi {
#Autowired
private PersonService personService;
#Autowired
private ObjectMapper objectMapper;
#Override
#GetMapping(path = "/persons")
public ResponseEntity<List<Person>> getPersons(
#RequestParam(required = false) String fields) {
List<Person> persons = this.personService.getPersons();
// Filter fields
if (StringUtils.isNotBlank(fields)) {
configureFilter(fields);
}
return ResponseEntity.status(HttpStatus.OK).body(persons);
}
private void configureFilter(String fields) {
Set<String> fieldsToKeep = new HashSet<>();
fieldsToKeep.add(fields);
objectMapper.addMixIn(Person.class, PersonDynamicFilterMixIn.class);
FilterProvider filterProvider = new SimpleFilterProvider().
addFilter("dynamicFilter", SimpleBeanPropertyFilter.filterOutAllExcept(fieldsToKeep));
objectMapper.setFilterProvider(filterProvider);
}
}
As you can see, the return of the method is ResponseEntity<List<Person>> (I can't change it to JacksonMappingValue, it is from the PersonApi interface) and we are returning with ResponseEntity.status(HttpStatus.OK).body(persons) (so I can't manually write the JSON response with the objectMapper myself);.
Under the hood, Spring is using Jackson ObjectMapper to do the conversion. I would like to configure that ObjectMapper when the fields request parameter is specified.
I also want the ObjectMapper configuration to be the same as Spring's default.
I can't use JsonViews because otherwise it is not dynamic anymore.
Could someone show me how I need to configure Spring to do that ? I tried to use these kind of things in SpringConfiguration, but then I end up with some of my tests not working anymore. For some tests, if I run a single test it passes, if I run the whole test suite that test doesn't pass anymore ...
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter(objectMapper()));
}
#Bean
public ObjectMapper objectMapper() {
return Jackson2ObjectMapperBuilder.json().build();
}
Thank you for your help !
I have a bundle that provides a service.
My bundle implementation looks like this:
class ServiceImpl implements Service
{
Object value;
#Override
public void setValue(Object value)
{
this.value = value;
}
#Override
public Object getValue()
{
return value;
}
}
In my java application, I load this bundle to OSGI framework, and create TWO references to the service, in an attempt to have two objects with different values for "value".
Unfortunately, this does not seem to work. The service always returns the last value set by either objects. How can I overcome this issue?
Here's an example for the problem:
Service object1 = context.getService(reference1);
Service object2 = context.getService(reference2);
Integer one= 1;
Integer two =2;
object1.setValue(1);
object2.setValue(2);
System.out.println(object1.getValue() ); //returns 2 !!!!!!!!!!!!!!!!!!
System.out.println(object2.getValue() ); //returns 2
I used ServiceFactory but it seems not useful for my case. What should I do? Thanks.
Both BJ and Balazs offer valuable information, but no solution that works with current versions of the OSGi specification.
What you can do is register your service with a second "Factory" interface. This factory then allows you to create instances of the service. Because you probably don't want to do that manually, you can hide this logic in a ServiceTracker.
There are a few "downsides" to this approach. First of all, you need to register the service and have the instance implement both Factory and Service. Secondly, you always have to use this custom ServiceTracker to access it. If you use a dependency manager that allows you to extend its dependencies (such as Apache Felix Dependency Manager) you can easily hide all of this in a custom ServiceDependency.
Anyway, to show you that this actually works, here is a simple example:
public class Activator implements BundleActivator {
#Override
public void start(final BundleContext context) throws Exception {
context.registerService(Service.class.getName(), new FactoryImpl(), null);
ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() {
#Override
public Object addingService(ServiceReference reference) {
Object service = context.getService(reference);
if (service instanceof Factory) {
return ((Factory) service).createInstance();
}
return service;
}
#Override
public void modifiedService(ServiceReference reference,
Object service) {
// TODO Auto-generated method stub
}
#Override
public void removedService(ServiceReference reference,
Object service) {
// TODO Auto-generated method stub
}
};
ServiceTracker st1 = new ServiceTracker(context, Service.class.getName(), customizer);
ServiceTracker st2 = new ServiceTracker(context, Service.class.getName(), customizer);
st1.open();
st2.open();
Service s1 = (Service) st1.getService();
Service s2 = (Service) st2.getService();
s1.setValue("test1");
s2.setValue("test2");
System.out.println(s1.getValue());
System.out.println(s2.getValue());
}
#Override
public void stop(BundleContext context) throws Exception {
}
static interface Factory {
public Object createInstance();
}
static class FactoryImpl extends ServiceImpl implements Factory, Service {
#Override
public Object createInstance() {
return new ServiceImpl();
}
}
static interface Service {
public void setValue(Object value);
public Object getValue();
}
static class ServiceImpl implements Service {
private Object m_value;
#Override
public void setValue(Object value) {
m_value = value;
}
#Override
public Object getValue() {
return m_value;
}
}
}
You need to wait for R6. Pre-R6, each bundle can be exposed to at most one instance of a service. Even registering a ServiceFactory will not change that since the framework will cache the service object from the ServiceFactory to return to the bundle on subsequent calls to getService.
In R6, we introduce service scopes which allows a service implementation to return multiple service objects to a bundle. Using this requires both the service provider and the service consumer to use new API added in R6.
You can play with this now as it is implemented in Eclipse Equinox Luna.
Even if you use ServiceFactory, for the same bundle the same service object will be returned.
There might be a PrototypeServiceFactory in the future as there is an RFP about it: https://github.com/osgi/design/tree/master/rfcs/rfc0195
That would fit to your needs.
Although there might be a PrototypeServiceFactory in the future, I think it is better to solve this use-case programmatically by yourself. E.g.:
Instead of creating a mutuable OSGi service (I do not think creating mutuable services is a good idea) create a factory.
On the client side you would use:
BusinessLogicFactory factory = context.getService(reference);
BusinessLogic object1 = factory.createInstance();
BusinessLogic object2 = factory.createInstance();
...
I want to convert Optional<BigDecimal> in morphia. I created BigDecimalConverter, and it works fine. Now I want to create OptionalConverter.
Optional can hold any object type. In my OptionalConverter.encode method I can extract underlying object, and I'd like to pass it to default mongo conversion. So that if there is string, I'll just get string, if there is one of my entities, I'll get encoded entity. How can I do it?
There are two questions:
1. How to call other converters?
2. How to create a converter for a generic class whose type parameters are not statically known?
The first one is possible by creating the MappingMongoConveter and the custom converter together:
#Configuration
public class CustomConfig extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
// ...
}
#Override
#Bean
public Mongo mongo() throws Exception {
// ...
}
#Override
#Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter mmc = new MappingMongoConverter(
mongoDbFactory(), mongoMappingContext());
mmc.setCustomConversions(new CustomConversions(CustomConverters
.create(mmc)));
return mmc;
}
}
public class FooConverter implements Converter<Foo, DBObject> {
private MappingMongoConverter mmc;
public FooConverter(MappingMongoConverter mmc) {
this.mmc = mmc;
}
public DBObject convert(Foo foo) {
// ...
}
}
public class CustomConverters {
public static List<?> create(MappingMongoConverter mmc) {
List<?> list = new ArrayList<>();
list.add(new FooConverter(mmc));
return list;
}
}
The second one is much more difficult due to type erasure. I've tried to create a converter for Scala's Map but haven't found a way. Unable to get the exact type information for the source Map when writing, or for the target Map when reading.
For very simple cases, e.g. if you don't need to handle all possible parameter types, and there is no ambiguity while reading, it may be possible though.
I have a RESTful service that needs to return only a few of the XmlElements if "selectors" are submitted with the request. The URL will take the form of:
/merchants/{merchantId}/profile?selectors=<field1|field2|....|fieldN>
The selectors are optional, and so far I have implemented the service for the full set of elements to be returned for {merchantId} without selectors specified. Now I'm trying to figure out how to add in this added functionality. I'm sure this is covered in documentation but I can't find where. Any RTFM pointers would be appreciated. Thanks.
EclipseLink JAXB (MOXy) does not currently offer a mechanism to selectively indicate which fields/properties are included on a per marshal operation. This sounds like an interesting use case. I would appreciate if you could enter this as an enhancement request using the following link:
https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EclipseLink
Below is an example of how you could use a stateful XmlAdapter to implement this use case by exploiting the fact that a JAXB (JSR-222) will not marshal an element when the value is null (see: http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html).
FieldAdapter
Since we are going to leverage stateful XmlAdapters we're going to need one per field. Since all our XmlAdapters will perform the same logic we can create a super class that the others can extend from.
package forum13094195;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class FieldAdapter<T> extends XmlAdapter<T, T> {
private boolean include;
public FieldAdapter() {
this.include = true;
}
public FieldAdapter(boolean include) {
this.include = include;
}
#Override
public T marshal(T value) throws Exception {
if(include) {
return value;
}
return null;
}
#Override
public T unmarshal(T value) throws Exception {
return value;
}
}
Field1Adapter
package forum13094195;
public class Field1Adapter extends FieldAdapter<String> {
public Field1Adapter() {}
public Field1Adapter(boolean include) {
super(include);
}
}
Field2Adapter
package forum13094195;
public class Field2Adapter extends FieldAdapter<Integer>{
public Field2Adapter() {}
public Field2Adapter(boolean include) {
super(include);
}
}
Field3Adapter
package forum13094195;
public class Field3Adapter extends FieldAdapter<String> {
public Field3Adapter() {}
public Field3Adapter(boolean include) {
super(include);
}
}
Merchant
The #XmlJavaTypeAdapter annotation is used to specify an XmlAdapter on a field/property.
package forum13094195;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Merchant {
#XmlJavaTypeAdapter(Field1Adapter.class)
String field1;
#XmlJavaTypeAdapter(Field2Adapter.class)
int field2;
#XmlJavaTypeAdapter(Field3Adapter.class)
String field3;
}
Demo
The demo code below demonstrates how to set a stateful XmlAdapter on the Marshaller.
package forum13094195;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Merchant.class);
Merchant merchant = new Merchant();
merchant.field1 = "A";
merchant.field2 = 2;
merchant.field3 = "C";
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(merchant, System.out);
marshaller.setAdapter(new Field1Adapter(false));
marshaller.setAdapter(new Field2Adapter(false));
marshaller.setAdapter(new Field3Adapter(true));
marshaller.marshal(merchant, System.out);
}
}
Output
Below is the output from running the demo code. By default the entire object is marshalled out. The second document marshalled does not contain the fields we excluded.
<?xml version="1.0" encoding="UTF-8"?>
<merchant>
<field1>A</field1>
<field2>2</field2>
<field3>C</field3>
</merchant>
<?xml version="1.0" encoding="UTF-8"?>
<merchant>
<field3>C</field3>
</merchant>
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
In EclipseLink 2.5.0 we released a new feature called Object Graphs that enables you to marshal/unmarshal a subset of mapped fields/properties.
// Create the Object Graph
ObjectGraph subset = JAXBHelper.getJAXBContext(jc).createObjectGraph(Merchant.class);
subset.addAttributeNodes("field1", "field1", "fieldN");
// Output XML - Based on Object Graph
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, subset);
marshaller.marshal(customer, System.out);
For More Information
http://blog.bdoughan.com/2013/03/moxys-object-graphs-partial-models-on.html
I am trying to a find a good design for the following scenario.
I have a POST rest service which will be given an array of services as data. And which should in turn be calling them one by one to aggregate results on the server and send them back to the client.
#Path("/resource1")
#Path("/resource2")
#Path("/collection")
Post data to /collection
{["serviceName": "resource1", "data":"test1"], ["serviceName":"resource2","data":"test2"]}
The reason i need the resource1 and resource2 are, because those services can be called standalone also. I want to reuse the same setup if possible.
Is there any way to do this.
I am using jersey with spring.
Not sure what these resources have in common. If the post method has the same signature for all of them, you could have an abstract class or interface they implement defining the post method and can try using ResourceContext.matchResource to do this. E.g. something like this:
public abstract class AbstractResource {
public abstract String post(Object data);
}
#Path("/resource1")
public class Resource1 extends AbstractResource {
#POST
public String post(String data) {
// do something
}
}
#Path("/collection")
public class CollectionResource {
#Context
private ResourceContext rc;
#POST
#Consumes("application/json")
public String post(List<PostRequest> postRequests) {
StringBuilder result = new StringBuilder();
for (PostRequest pr : postRequests) {
// should wrap this in try-catch
AbstractResource ar = rc.matchResource(pr.resource,
AbstractResource.class);
sb.append(ar.post(pr.data));
}
return result.toString();
}
}
#XmlRootElement
public class PostRequest {
public String resource;
public String data;
}
Hopefully you got the idea and will be able to play with it and tweak it to fit your needs.