I'm using Spring MVC to handle JSON POST requests. Underneath the covers I'm using the MappingJacksonHttpMessageConverter built on the Jackson JSON processor and enabled when you use the mvc:annotation-driven.
One of my services receives a list of actions:
#RequestMapping(value="/executeActions", method=RequestMethod.POST)
public #ResponseBody String executeActions(#RequestBody List<ActionImpl> actions) {
logger.info("executeActions");
return "ACK";
}
I have found that Jackson maps the requestBody to a List of java.util.LinkedHashMap items (simple data binding). Instead, I would like the request to be bound to a List of typed objects (in this case "ActionImpl").
I know this is easy to do if you use Jackson's ObjectMapper directly:
List<ActionImpl> result = mapper.readValue(src, new TypeReference<List<ActionImpl>>() { });
but I was wondering what's the best way to achieve this when using Spring MVC and MappingJacksonHttpMessageConverter. Any hints?
Thanks
I have found that you can also work around the type erasure issue by using an array as the #RequestBody instead of a collection. For example, the following would work:
public #ResponseBody String executeActions(#RequestBody ActionImpl[] actions) { //... }
I suspect problem is due to type erasure, i.e. instead of passing generic parameter type, maybe only actions.getClass() is passed; and this would give type equivalent of List< ?>.
If this is true, one possibility would be to use an intermediate sub-class, like:
public class ActionImplList extends ArrayList<ActionImpl> { }
because this will the retain type information even if only class is passed.
So then:
public #ResponseBody String executeActions(#RequestBody ActionImplList actions)
would do the trick. Not optimal but should work.
I hope someone with more Spring MVC knowledge can shed light on why parameter type is not being passed (perhaps it's a bug?), but at least there is a work around.
For your information, the feature will be available in Spring 3.2 (see https://jira.springsource.org/browse/SPR-9570)
I just tested it on current M2 and it works like a charm out of the box (no need to provide additionnal annotation to provide the parameterized type, it will be automatically resolved by new MessageConverter)
This question is already old, but I think I can contribute a bit anyway.
Like StaxMan pointed out, this is due to type erasure. It definitely should be possible, because you can get the generic arguments via reflection from the method definition. However, the problem is the API of the HttpMessageConverter:
T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
Here, only List.class will be passed to the method. So, as you can see, it is impossible to implement a HttpMessageConverter that calculates the real type by looking at the method parameter type, as that is not available.
Nevertheless, it is possible to code your own workaround - you just won't be using HttpMessageConverter. Spring MVC allows you to write your own WebArgumentResolver that kicks in before the standard resolution methods. You can for example use your own custom annotation (#JsonRequestBody?) that directly uses an ObjectMapper to parse your value. You will be able to provide the parameter type from the method:
final Type parameterType= method.getParameterTypes()[index];
List<ActionImpl> result = mapper.readValue(src, new TypeReference<Object>>() {
#Override
public Type getType() {
return parameterType;
}
});
Not really the way TypeReference was intended to be used I presume, but ObjectMapper doesn't provide a more suitable method.
Have you tried declaring the method as:
executeActions(#RequestBody TypeReference<List<ActionImpl>> actions)
I haven't tried it, but based on your question it's the first thing I would try.
Related
I'm implementing JMS in a Spring Boot application. Everything is going well. However I'm very surprised at the tight coupling between JSON messages and Java objects. I am looking for some direction on a more flexible solution.
Going through examples and using the MappingJackson2MessageConverter, everything is great as long as you are sending and receiving in the same application. Under the covers it's extremely tightly coupled to the java object. If I have a simple java object called person:
package acme.receivingapp.dto;
public class Person {
private String firstName;
private String lastName;
...
}
When the JmsTemplate turns that into a message the JSON looks generic enough:
{"firstName":"John", "lastName":"Doe"}
However it includes this property:
"_type" : "acme.superapp.dto.Person"
If the JmsListener isn't using that exact Java class, it throws an exception. That's true even if the class is functionally the same as in this example where it's effectively the same class but just in a different package:
package wonderco.sendingapp.dto;
public class Person {
private String firstName;
private String lastName;
...
}
We will be receiving messages from many external entities from mainframes, python apps, .Net, etc. I cannot require them to include our object types in a _type property.
I could create my own MessageConverter specifically for a Person object, but if we have hundreds of more messages / java classes it would be unwieldy to have so many message converters. I would need to design something more generic that can work for any type of JSON message / java class.
Before I go down the path of designing my own generic solution is there anything more generic that works like Spring RestControllers and Spring RestTemplates in the sense that the JSON messages aren't so tightly coupled to the very specific Java classes? I feel like I can't possibly be the first person trying to crack this nut.
I think I've got a handle on this. I'll try to explain it to hopefully help the next person who is new to Spring / JMS.
As M.Deinum points out, unlike a REST endpoint, a queue could potentially contain many different types of messages. Even if your implementation will only have one type of message per queue. Because queues allow any number of different messages that was the design for the provided MappingJackson2MessageConverter. Because the assumption was made there will always be multiple types of messages, there must be a mechanism to determine how to unmarshal the JSON for different types of messages into the correct type of Java Object.
All the examples you'll find of using a MappingJackson2MessageConverter will have this setup in them:
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTypeIdPropertyName("_type");
That's telling the message converter to set the object type in a property called _type when creating a message or to read the object type from that property when reading a message. There's no magic in that _type property. It's not a standard. It's just what the Spring folks used in their examples and then a bazillion people cut and pasted it. So for your own messages, you can change that to a more appropriate property name if you like. So in my example, I might call the property acme_receivingapp_message_type if I wanted. I would then tell the external entities sending me messages to include that property with the message type.
By default, the MappingJackson2MessageConverter will write the object type into whatever property name you chose (_type or whatever) as the fully qualified class name. In my example, it's acme.receivingapp.dto.Person. When a message is received, it looks at the type property to determine what type of Java object to create from the JSON.
Pretty straightforward so far, but still not very convenient if the people sending me messages are not using Java. Even if I can convince everyone to send me acme.receivingapp.dto.Person, what happens if I refactor that class from Person to Human? Or even just restructure the packages? Now I've got to go back and tell the 1,000 external entities to stop sending the property as acme.receivingapp.dto.Person and now send it as acme.receivingapp.dto.Human?
Like I stated in my original question, the message and Java class are being very tightly coupled together which doesn't work when you are dealing with external systems/entities.
The answer to my problem is right in the name of the **Mapping**Jackson2MessageConverter message converter. The key there is the "mapping". Mapping refers to mapping message types to Java classes which is what we want. It's just that, by default, because no mapping information is provided, the MappingJackson2MessageConverter simply uses the fully qualified java class names for creating and receiving messages. All we need to do is provide the mapping information to the message converter so it can map from friendly message-types (e.g.. "Person") to specific classes within our application (e.g. acme.receivingapp.dto.Person).
If you wanted your external systems/entities that will be sending you messages to simply include the property acme_receivingapp_message_type : Person and you wanted that unmarshalled to an acme.receivingapp.dto.Person object when it's received on your end, you'd setup your message converter like this:
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("acme_receivingapp_message_type");
// Set up a map to convert our friendly message types to Java classes.
Map<String, Class<?>> typeIdMap = new HashMap<>();
typeIdMap.put("Person", acme.receivingapp.dto.Person.class);
converter.setTypeIdMappings(typeIdMap);
return converter;
}
That solves the problem of tight coupling between the message type property and Java class names. But what if you'll only be dealing with a single message type in your queue and don't want the people sending messages to have to include any property to indicate the message type? Well MappingJackson2MessageConverter simply doesn't support that. I tried using a "null" key in the map and then leaving the property off the message and unfortunately it doesn't work. I wish it did support that "null" mapping to use when the property wasn't present.
If you have the scenario where your queue will only deal with one type of message and you don't want the sender to have to include a special property to indicate the message type, you'll likely want to write your own message converter. That convertor will blindly unmarshal the JSON to the one java class you'll always be dealing with. Or maybe you opt to just receive it as a TextMessage and unmarshal it in your listener.
Hopefully this helps someone because I found it quite confusing initially.
I'm reacting to this thread because I have exactly the same feeling!
Why spring isn't able to deserialise the event based on the prototype function that implement the #JmsListener ?
If you have a function like
#JmsListener(destination = "#{beanQueue.queueName}")
public void onEvent(MyEvent event) {
// Do what you want
}
Why do we need to explicitly define the _type property that allow to know the java type output? We can extract it from the parameter function.
I don't perform deep search under the hood, but it look reasonable to me
[EDIT] After some debugging and some quick research, I found a solution. I'm not convinced that it's the more elegant solution, but at least it allow to have a kind of generic converter.
Convert all to String
Convert automatically all event to the java.lang.String type, in order to have a generic _type for all consumer
It can be done by encapsulate the actual MappingJackson2MessageConverter
#Bean
public MessageConverter jsonMessageConverter() {
final ObjectMapper objectMapper = new ObjectMapper();
// Setup the object mapper
final MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
messageConverter.setObjectMapper(objectMapper);
messageConverter.setTargetType(MessageType.TEXT);
messageConverter.setTypeIdPropertyName("_type");
return new MessageConverter() {
#Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
try {
final String stringValue = objectMapper.writeValueAsString(object);
return messageConverter.toMessage(stringValue, session);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
#Override
public Object fromMessage(Message message) throws JMSException, MessageConversionException {
return messageConverter.fromMessage(message);
}
};
}
Read all from String
In order to read all from String without need to rewrite all the actual spring implementation, we can take benefit of the ConversionService
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter((Converter<String, MyEvent>) source -> {
try {
return new ObjectMapper().readValue(source, MyEvent.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
});
}
Limitation
There is some limitation, since the event is now transfered as a String, which is not elegant at all..
I don't actually investigate with the org.springframework.jms.support.converter.MessageType that allow to define other type of message.
In addition, it force the client to always define a converter for all event that are listening inside the application.
Using LifeRay portal and ElasticSearch, Serializing custom object composed from ServiceModel Objects, Serialisation goes fine:
public String toJSON(){
return JSONFactoryUtil.looseSerializeDeep(this);
}
I index this into ES which is also fine, it contains list of those objects as well as single object, no problem.
When I Deserialize this I get this Error:
10:10:53,972 ERROR [ExceptionHandlerBridgeImpl:78] jodd.json.JsonException: Default ctor not found for: eu.project.drives.platform.model.model.TainingProvider
For each parameter which is Object from Service Model.
Code (should be ok as well, example for one field):
JSONObject obj = JSONFactoryUtil.createJSONObject(h.getSourceAsString());
TainingProvider t = JSONFactoryUtil.looseDeserialize(obj.getString("provider"), TainingProvider.class);
I cannot simply induce the Default constructor since it is generated by service builder nor I can do the "TainingProviderImpl.class" since it is different project but the Impl class should be what is called through the "TainingProvider.class" and it includes the default constructor.
Thank you.
The provided type when doing a deserialize is an interface in your example, so the internal Parser (here Jodd) might not find an implementation class to use as a bean class.
I did not find a nice solution, but used the internal Jodd parser directly.
When you subclass jodd.json.JsonParser you can overwrite the protected method for instantiation.
#Override
protected Object newObjectInstance(Class targetType) {
if (targetType.isAssignableFrom(TainingProvider.class)) {
return TainingProviderLocalServiceUtil.createTainingProvider(0L);
}
return super.newObjectInstance(targetType);
}
Now you can use the parser directly via parser.parse(obj.getString("provider"), TainingProvider.class)
I am not sure if it possible to hook in this instantiation hints to Liferays JSONFactoryUtil, which would be nicer instead of having a direct dependency to the jodd Parser in your module.
i'm using the Restlet library for a WS server and i've recently switched from XStream/Jettison to Jackson as a JSON serializer/deserializer because of some issues.
A first drawback is that my ArrayList< Profile > (previously a Vector with Jettison) it doesn't wrap the list of Profiles when serialized and the JSON instead of "Profile:[{firstProfile}, {secondProfile}]" it looks like: [{firstProfile}, {secondProfile}]
I can overcome to this issue in the client telling manually which is the correct mapping but i would prefer to use a KVC approach.
I've looked around and it seems that it's a known issue: http://wiki.fasterxml.com/JacksonPolymorphicDeserialization (5.1 Missing type information on Serialization) that it suggest to:
Use arrays instead of Lists
Sub-class list, using class MyPojoList extends ArrayList { }
Force use of specific root type
the simplest way it should be to return an "Profile[] profile" array but it seems not working, before trying the other solutions i've rechecked around and it seems that you can use a #XmlRootElement(name = "Profile") to wrap the JSON root element: http://jira.codehaus.org/browse/JACKSON-163?focusedCommentId=213588&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-213588
so for using JAXB annotations with Jackson you need to configure the objectMapper: http://wiki.fasterxml.com/JacksonJAXBAnnotations
but in restlet to do so you need to override createObjectMapper to pass a Custom converter (see: http://restlet-discuss.1400322.n2.nabble.com/Set-custom-objectMapper-to-Jackson-Extension-td6287812.html and http://restlet-discuss.1400322.n2.nabble.com/Jackson-Mix-in-Annotations-td6211060.html#a6231831)
this is what i'm trying now! the question is there a more straightforward way to achieve this??
Thanks!!
the solution for me is to annotate the Profile class with:
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
public class Profile extends Element implements Serializable {
and now the json now looks like:
{"Profile":{ ... }}
and the return type is a Sub-classed list:
public class ProfileList extends ArrayList<Profile>
{}
see http://wiki.fasterxml.com/JacksonPolymorphicDeserialization 5.1
I think what you want is not really available in a sense that JAX-B seems to have some rules on how to deal with lists. See this converstation on the RESTeasy mailing list
I have a Domain Specific Language, and I would like to register objects that can be instantiated inside.
For instance a class that can do httprequests.
[IoC("HttpRequest", typeof(DslScriptObject), IoCAttribute.IoCLifestyleType.Transient)]
internal class WebRequestDslObj : DslScriptObject
{
[DslNew]
public WebRequestDslObj() : this(null, null)
{}
[DslNew]
public WebRequestDslObj([DslParam("uri")]string uristring, [DslOptionalParam("contenttype")] string contenttype) : this(uristring, null)
{}
}
I then have a class that maps types from my dsl datatypes to c# datatypes (I have them as an IList if that makes any difference), and this works ok, if I do not use Castle to instantiate the object.
But as soon as I want to use IoC to autoregister the various types, then I dont know what to do about the constructors. I have tried to look at setting a CustomComponentActivator, but I got stuck at not being able to find any good example or documentation. Is that a viable path to take? (and will I be able to get around the funny special case for null parameters?)
Anyone have an example of where I can start?
So what are you trying to do with Windsor, because I'm not sure I see where you're going with it...
If you want to affect how component gets register in Windsor, for example rename parameters, you can write custom ComponentModel construction contributor to do it.
Method chaining is the only way I know to build fluent interfaces.
Here's an example in C#:
John john = new JohnBuilder()
.AddSmartCode("c#")
.WithfluentInterface("Please")
.ButHow("Dunno");
Assert.IsNotNull(john);
[Test]
public void Should_Assign_Due_Date_With_7DayTermsVia_Invoice_Builder()
{
DateTime now = DateTime.Now;
IInvoice invoice = new InvoiceBuilder()
.IssuedOn(now)
.WithInvoiceNumber(40)
.WithPaymentTerms(PaymentTerms.SevenDays)
.Generate();
Assert.IsTrue(invoice.DateDue == now.AddDays(7));
}
So how do others create fluent interfaces. How do you create it? What language/platform/technology is needed?
The core idea behind building a fluent interface is one of readability - someone reading the code should be able to understand what is being achieved without having to dig into the implementation to clarify details.
In modern OO languages such as C#, VB.NET and Java, method chaining is one way that this is achieved, but it's not the only technique - two others are factory classes and named parameters.
Note also that these techniques are not mutually exclusive - the goal is to maximize readabilty of the code, not purity of approach.
Method Chaining
The key insight behind method chaining is to never have a method that returns void, but to always return some object, or more often, some interface, that allows for further calls to be made.
You don't need to necessarily return the same object on which the method was called - that is, you don't always need to "return this;".
One useful design technique is to create an inner class - I always suffix these with "Expression" - that exposes the fluent API, allowing for configuration of another class.
This has two advantages - it keeps the fluent API in one place, isolated from the main functionality of the class, and (because it's an inner class) it can tinker with the innards of the main class in ways that other classes cannot.
You may want to use a series of interfaces, to control which methods are available to the developer at a given point in time.
Factory Classes
Sometimes you want to build up a series of related objects - examples include the NHibernate Criteria API, Rhino.Mocks expectation constraints and NUnit 2.4's new syntax.
In both of these cases, you have the actual objects you are storing, but to make them easier to create there are factory classes providing static methods to manufacture the instances you require.
For example, in NUnit 2.4 you can write:
Assert.That( result, Is.EqualTo(4));
The "Is" class is a static class full of factory methods that create constraints for evaluation by NUnit.
In fact, to allow for rounding errors and other imprecision of floating point numbers, you can specify a precision for the test:
Assert.That( result, Is.EqualTo(4.0).Within(0.01));
(Advance apologies - my syntax may be off.)
Named Parameters
In languages that support them (including Smalltalk, and C# 4.0) named parameters provide a way to include additional "syntax" in a method call, improving readability.
Consider a hypothetical Save() method that takes a file name, and permissions to apply to the file after saving:
myDocument.Save("sampleFile.txt", FilePermissions.ReadOnly);
with named parameters, this method could look like this:
myDocument.Save(file:"SampleFile.txt", permissions:FilePermissions.ReadOnly);
or, more fluently:
myDocument.Save(toFile:"SampleFile.txt", withPermissions:FilePermissions.ReadOnly);
You can create a fluent interface in any version of .NET or any other language that is Object Oriented. All you need to do is create an object whose methods always return the object itself.
For example in C#:
public class JohnBuilder
{
public JohnBuilder AddSmartCode(string s)
{
// do something
return this;
}
public JohnBuilder WithfluentInterface(string s)
{
// do something
return this;
}
public JohnBuilder ButHow(string s)
{
// do something
return this;
}
}
Usage:
John = new JohnBuilder()
.AddSmartCode("c#")
.WithfluentInterface("Please")
.ButHow("Dunno");
AFAIK, the term fluent interface does not specify a specific technology or framework, but rather a design pattern. Wikipedia does have an extensive example of fluent interfaces in C♯.
In a simple setter method, you do not return void but this. That way, you can chain all of the statements on that object which behave like that. Here is a quick example based on your original question:
public class JohnBuilder
{
private IList<string> languages = new List<string>();
private IList<string> fluentInterfaces = new List<string>();
private string butHow = string.Empty;
public JohnBuilder AddSmartCode(string language)
{
this.languages.Add(language);
return this;
}
public JohnBuilder WithFluentInterface(string fluentInterface)
{
this.fluentInterfaces.Add(fluentInterface);
return this;
}
public JohnBuilder ButHow(string butHow)
{
this.butHow = butHow;
return this;
}
}
public static class MyProgram
{
public static void Main(string[] args)
{
JohnBuilder johnBuilder = new JohnBuilder().AddSmartCode("c#").WithFluentInterface("Please").ButHow("Dunno");
}
}
Sometime ago I had the same doubts you are having now. I've done some research and now I'm writing a series of blog posts about techinics of designing a fluent interface.
Check it out at:
Guidelines to Fluent Interface design in C# part 1
I have a section there about Chaining X Nesting that can be interesting to you.
In the following posts I will talk about it in a deeper way.
Best regards,
André Vianna
Fluent interface is achieved in object oriented programming by always returning from your methods the same interface that contains the method. Consequently you can achieve this effect in java, javascript and your other favorite object oriented languages, regardless of version.
I have found this technique easiest to accomplish through the use of interfaces:
public interface IFoo
{
IFoo SetBar(string s);
IFoo DoStuff();
IFoo SetColor(Color c);
}
In this way, any concrete class that implements the interface, gets the fluent method chaining capabilities. FWIW.. I wrote the above code in C# 1.1
You will find this technique littered throughout the jQuery API
A couple of things come to mind that are possible in .Net 3.5/C# 3.0:
If an object doesn't implement a fluent interface, you could use Extension Methods to chain your calls.
You might be able to use the object initialization to simulate fluent, but this only works at instantiation time and would only work for single argument methods (where the property is only a setter). This seems hackish to me, but the there it is.
Personally, I don't see anything wrong with using function chaining if you are implementing a builder object. If the builder object has chaining methods, it keeps the object you are creating clean. Just a thought.
This is how I've built my so called fluent interfaces or my only forary into it
Tokenizer<Bid> tkn = new Tokenizer<Bid>();
tkn.Add(Token.LambdaToken<Bid>("<YourFullName>", b => Util.CurrentUser.FullName))
.Add(Token.LambdaToken<Bid>("<WalkthroughDate>",
b => b.WalkThroughDate.ToShortDateString()))
.Add(Token.LambdaToken<Bid>("<ContactFullName>", b => b.Contact.FullName))
.Cache("Bid")
.SetPattern(#"<\w+>");
My example required .net 3.5 but that's only cause of my lambda's. As Brad pointed out you can do this in any version of .net. Although I think lambda's make for more interesting possibilities such as this.
======
Some other good examples are nHibernate's Criteria API, there is also a fluent nhibernate extension for configuring nhibernate but I've never used it
Dynamic keyword in C# 4.0 will make it possible to write dynamic style builders. Take a look at following article about JSON object construction.