Spring MVC: Customizing view response (Json/XML) based on header or parameter - spring

I have a Spring MVC application which returns Json and Xml based on what is requested per client call. I am using Jackson and Xstream to let Spring do the de-serialization of my java object into json or xml output.
My java object contains a bunch of attributes, at least 30. I would like to know if there is a way I can let Spring control which fields of my java object will be present in the json or xml based on a header or parameter attribute. So the client application will be able to identify itself and the backend will return only the fields necessary or "visible" for that specific client app. Of course I could go to the nasty approach of hard coding, but I would not like to do that as the number of client applications can increase or decrease and having a deployment anytime it happens with code changes is out of context.
Is there a way to instruct spring/jackson/xstream to control the output based on some providaded value?
I did a quick implementation and my current solution works like this: I have an xml with a list of client IDs (I use these ids to identify my client app) and for each ID I have a list of attributes that the client app needs from the java object. I created a interceptor and between the controller and the view, my interceptor gets the header information with the client ID, get the list of attributes and using the BeanWrapper (http://docs.spring.io/spring/docs/2.0.x/reference/validation.html) to create a new object with only the attributes required by the client with data, all the others remain null (I instruct Jackson and Xtream) to ignore null attributes. This approach works fine but I was wondering if there is another/better way to do this.
Thank you
TL

Related

Get Jackson ObjectMapper in Quarkus

I am writing a custom OpenApiConfigurator that adds some examples to my api dynamically.
When I add the examples using the value field of io.smallrye.openapi.api.models.examples.ExampleImpl, which is an object, the example is null in swagger-ui. It only works when I added the actual json.
To add the actual json I have to generate it from my response dto using Jackson. But how can I access the quarkus object mapper, for which I have some customisations using ObjectMapperCustomizer, if in the OpenApiConfigurator CDI is not available?
It's actually possible to access the CDI container statically with Arc.container().instance(ObjectMapper::class.java).get()
That solved it for me.

Are template engines (i.e. Thymeleaf) necessary for Spring Boot applications?

I am currently working on a Spring Boot project and I am fairly new to template engines. This will also be my first own private project with Spring Boot.
I would like to know whether it is necessary to include a template engine, such as Thymeleaf, while developing a web application with Spring Boot. I'm using PostegreSQL for the database.
I read under another post that a template engine is not needed, if the backend framework uses JSON for data exchange, because template engines are for rendering retrieved data to HTML for the client. I retrieve JSON objects from the database, can I leave template engines out of my project then?
If any more details are needed, leave a comment below.
No they aren't necessary, in fact most new projects that require web-pages are using single page applications now like Angular, React, Vue, ... over thymeleaf or jsp.
Aside from that a Spring project doesn't always need web pages, for instance when you are just creating a REST API for other applications to call on, or when you are automating things like: a mail service / printing / ... You name it.
However, when you DO want a simple solution with some pages that aren't all that dynamic or complex, pivotal / VMware does recommend to use thymeleaf (over jsp and other solutions) because it integrates easily.
I read under another post that a template engine is not needed, if the backend framework uses JSON for data exchange, because template engines are for rendering retrieved data to HTML for the client. I retrieve JSON objects from the database, can I leave template engines out of my project then?
This is partly true. Yes, Thymeleaf and alike are mostly intended to render data to HTML. They can render any text data, including JSON, but there are tools better suited for the job. On other hand it does not matter how you store the data in your database or what database you are using. You can't just skip rendering (serializing) the response so it does not matter how you store it. What matters is what you want to return as response. For HTML Thymeleaf or even JSP are suitable, but for JSON you may want to use Jackson or Gson instead.
You didn't mentioned the technology you are going to use, so for my examples I'll assume you intend to use Spring Web MVC. Lets take a look at "traditional" controller:
#Controller
public class GreetingController {
#GetMapping("/greeting")
public ModelAndView greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new ModelAndView("greeting", "greeting", new Greeting(name));
}
}
When you make GET request to "/greeting", Spring will call greeting and get the object it returns. In this case it contains the model (the data we want to render) and the view (the template file to use). Then it will try to find a view (something like greeting.html or greeting.jsp) and use template engine like Thymeleaf (or whatever else is configured) to render it (typically to HTML).
What if we want to return JSON instead? In this case we need to:
modify greeting to return Greeting instance instead of ModelAndView
Use RestController instead of Controller. This will tell Spring MVC that we want to directly serialize the object returned to JSON (or similar format) instead of using template to do that.
Here is the modified example:
#RestController
public class GreetingController {
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(name);
}
}
Spring MVC still needs some help to serialize the Greeting instance to JSON. But if you use Spring Boot and the web starter, you don't have to worry about it. It will include Jackson for you.
This is in no way exhaustive answer. As a matter of fact it skips a lot of details, but I hope nevertheless it is useful one. If you want to create REST API using JSON, this Building a RESTful Web Service guide is a good place to start. If you follow the Starting with Spring Initializr steps you'll get a project setup with only what is needed (well maybe with a bit extra but I would not worry too much about it).

Couchbase modify meta data experation using Spring

When using Spring Couchbase connector I can easily get version for optimistic locking by having this in my class:
public class MyClass {
#Version
private String version;
.... rest of class omitted ....
}
I'm now trying to find a similar way to get and be able to modify the meta data for expiration. I'm unable to find how to do this.
Can someone please give an example? Thanks!
With spring data couchbase library (until the latest Version 3.0.8.RELEASE), document expiry can be defined by using #Document(expiry = 10) or #Document(expiryExpression = "${valid.document.expiry}") on the class. There is also an optional boolean attribute touchOnRead which needs to be added with #Document, which would reset the expiry timer whenever the document is directly read. Please note that currently the expiry of an existing document cannot be read/modified directly with this library. One way would be to access the below APIs exposed by Couchbase's own java SDK (com.couchbase.client.java)
getAndTouch - allows you to retrieve a document while modifying its expiration time
touch - allows you to modify a document’s expiration time without otherwise accessing the document
You can find the method signatures of the above two here : http://docs.couchbase.com/sdk-api/couchbase-java-client-2.2.4/com/couchbase/client/java/Bucket.html
The above two APIs can be accessed via the spring data couchbase library as follows
couchbaseTemplate.getCouchbaseBucket().touch(...)
couchbaseTemplate.getCouchbaseBucket().getAndTouch(...)
The getCouchbaseBucket() method of the spring library returns a reference to com.couchbase.client.java.Bucket using which the touch and getAndTouch methods can be used.

REST and spring-mvc

Since REST based controller methods only return objects ( not views ) to the client based on the request, how can I show view to my user ? Or maybe better question what is a good way to combine spring-mvc web app with REST, so my user always get the answer, not in just ( for example ) JSON format, but also with the view ?
So far as I understood, REST based controller would be perfectly fitting to the mobile app ( for example twitter ), where views are handled inside the app and the only thing server has to worry about is to pass the right object to the right request. But what about the web app ?
I might be wrong in several things ( correct me if I am ), since I am trying to understand REST and I am still learning.
To simplify things - you basically have two options:
1) Build Spring MVC application.
2) Build REST backend application.
In case of first option - within your application you will have both backend and frontend (MVC part).
In case of second option you build only backend application and expose it through REST API. In most cases, you will need to build another application - REST client for your application. This is more flexible application because it gives you opportunity to access your backend application from various clients - for example, you can have Android, IOS applications, you can have web application implemented using Angular etc...
Please note, that thins are not so simple, you can within one application have both REST backend and REST client etc... This is just very very simplified in order that you get some general picture. Hope this clarified a little things.
There is some additional clarification related to REST and views worth learning. From your question, I can see that you mean "view" in a sense of UI(user interface) and typical MVC usage. But "view" can mean different things in a different contexts.
So:
JSON can be considered as a view for data
JSON is a representation of the resource, just like HTML is
JSON doesn't have style (unless you are not using a browser
extension, which most the users are not using)
The browser is recognizing HTML as a markup language and applying a
style to it
Both are media types
Both JSON and HTML are data formats
Both can be transferred over the wire
This method returns a view
#RequestMapping("/home")
String home(Model model) {
return "home"; // resources\templates\home.html
}
This method Returns String
#RequestMapping(value = "/home")
#ResponseBody
public String home() {
return "Success";
}
If you annotate a method with #ResponseBody, Spring will use a json mapper to generate the response. Instead of annotating every method with #ResponseBody you can annotate your class with #RestController.
If you want to return a view, you need to annotate the class with #Controller instead of #RestController and configure a viewresolver. Bij default spring will use thymeleaf as a viewresolver if you have spring-web as a dependency on the classpath. The return type of the method is a String that references the template to be rendered. The templates are stored in src/main/resources/templates.
You can find a guide on the spring website: https://spring.io/guides/gs/serving-web-content/

Read-only model property not serialized in Web API

As per the title, I'm seeing that my read-only model properties are not serialized in my Web API project. MVC 4 Web API, VS2010.
I've seen a multitude of posts like this stackoverflow question that state that the MVC 4 Web API beta did not support JSON serializing of read-only properties. But many additional references stated that the final release used JSON.NET instead of DataContractJsonSerializer so the issue should be resolved.
Has this issue been resolved or not? If not, am I forced to put in fake setters just to get serialization?
Correction, it does seem to work with JSON (sorry!), but XML exhibits the problem. So same question as before but in the context of XML serialization.
The default JSON serializer is now Json.NET. So readonly property serialization should work without you having to do anything at all.
For XML, in 4.5 we added this flag to the DataContractSerializer:
http://msdn.microsoft.com/en-us/library/vstudio/system.runtime.serialization.datacontractserializersettings.serializereadonlytypes.aspx
You should be able to write something like this:
config.Formatters.XmlFormatter.SetSerializer(myType, new DataContractSerializer(myType, new DataContractSerializerSettings() { SerializeReadOnlyTypes = true });
Place this code in a function called by GlobalConfiguration.Configure in the Application_Start. By default this would be WebApiConfig.Register().

Resources