Post a complex object using RestTemplate in Java - resttemplate

I want to post a complex object (CustomResponse) using RestTemplate
class CustomResponse { String name; Map<String, Employee> employeeMap; }
How can I accomplish it?
tried using postForEntity and postForObject. it doesn't work

Related

Spring controller return string as pure json

I am returning a string object from spring controller like
#RequestMapping(value = "/persons.html", method = RequestMethod.GET)
public #ResponseBody String listPersonHtml(Model model) {
return "{\"abc\":\"test\"}";
}
I am getting response on ui like "{\"abc\":\"test\"}",i want this response as
{"abc":"test"}
i.e pure json object.
what type of configuration I need?
On UI side,if I set Accept */* then I face this issue,if I set Accept text/html or Accept text/plain then no issue is there,but I can't change accept header.
I found the way.Its all about spring message-converters.I added MappingJackson2HttpMessageConverter in this list and this converter tries to convert string to json and produces this result.
Just add org.springframework.http.converter.StringHttpMessageConverter before MappingJackson2HttpMessageConverter so that StringHttpMessageConverter can come into action and string can be returned as it is.
Old question, but I just had to solve the same issue and most of the answers I found resulted misleading, so here's mine:
It all starts with the Controller, and Spring trying to answer a mapped request in the format that the invoking client is expecting. The client can inform this using different HTTP features, and there is where the different HttpMessageConverter implementations are involved. Spring pick's the format to answer based on different strategies, applied by the ContentNegotiationManager.
By prioritizing StringHttpMessageConverter over MappingJackson2XmlHttpMessageConverter you are only telling Spring to answer in "text/plain" format over "application/json", and it will work until a client specifies that is expecting a json response (this is mostly done by setting the Accept header in the request, although there are other ways to do it). The important thing is that if a client sets that header to "application/json", Spring will use MappingJackson2XmlHttpMessageConverter that will translate the Java String to a Json String, ending up with something like "{\"abc\":\"test\"}" instead of {"abc":"test"}
So, the real issue that every developer faces in this case is that MappingJackson2XmlHttpMessageConverter translates a Java String to a Json String, and in some cases, you might not need that, because the string contains valid json that needs to be returned without modifications. There are some configuration classes for this MessageConverter but I did'n went that road, because I need to return Strings like "raw" Json only in some specific endpoints (performance is the key driver). Here's an expample that resumes my "approach":
#RestController
#RequestMapping(value = "test", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class TestController {
#RequestMapping(method = RequestMethod.GET, value = "endpoint")
public JsonObject getSomeJson() {
return new JsonObject("{\"abc\":\"test\"}");
}
private static class JsonObject {
private String rawJsonValue;
JsonObject(String rawJsonValue) {
this.rawJsonValue = rawJsonValue;
}
#JsonValue #JsonRawValue
public String getRawJsonValue() {
return rawJsonValue;
}
}
}
#JsonValue and #JsonRawValue are Jackson annotations that tell MappingJackson2XmlHttpMessageConverter to treat the getRawJsonValue method result as the Json representation of JsonObject, without making any modification. The response of the endpoint will be {"abc":"test"}

Is there a way to customize the ObjectMapper used by Spring MVC without returning String?

I have a graph of objects that I'd like to return different views of. I don't want to use Jackson's #JsonViews to implement this. Right now, I use Jackson MixIn classes to configure which fields are shown. However, all my rest methods return a String rather than a type like BusinessCategory or Collection< BusinessCategory >. I can't figure out a way to dynamically configure the Jackson serializer based on what view I'd like of the data. Is there any feature built into Spring to configure which Jackson serializer to use on a per-function basis? I've found posts mentioning storing which fields you want in serialized in thread-local and having a filter send them and another post filtering based on Spring #Role, but nothing addressing choosing a serializer (or MixIn) on a per-function basis. Any ideas?
The key to me thinking a proposed solution is good is if the return type is an object, not String.
Here are the objects in my graph.
public class BusinessCategory implements Comparable<BusinessCategory> {
private String name;
private Set<BusinessCategory> parentCategories = new TreeSet<>();
private Set<BusinessCategory> childCategories = new TreeSet<>();
// getters, setters, compareTo, et cetera
}
I am sending these across the wire from a Spring MVC controller as JSON like so:
#RestController
#RequestMapping("/business")
public class BusinessMVC {
private Jackson2ObjectMapperBuilder mapperBuilder;
private ObjectMapper parentOnlyMapper;
#Autowired
public BusinessMVCfinal(Jackson2ObjectMapperBuilder mapperBuilder) {
this.mapperBuilder = mapperBuilder;
this.parentOnlyMapper = mapperBuilder.build();
parentOnlyMapper.registerModule(new BusinessCategoryParentsOnlyMapperModule());
}
#RequestMapping(value="/business_category/parents/{categoryName}")
#ResponseBody
public String getParentCategories(#PathVariable String categoryName) throws JsonProcessingException {
return parentOnlyMapper.writeValueAsString(
BusinessCategory.businessCategoryForName(categoryName));
}
}
I have configure the serialization in a MixIn which is in turn added to the ObjectMapper using a module.
public interface BusinessCategoryParentsOnlyMixIn {
#JsonProperty("name") String getName();
#JsonProperty("parentCategories") Set<BusinessCategory> getParentCategories();
#JsonIgnore Set<BusinessCategory> getChildCategories();
}
public class BusinessCategoryParentsOnlyMapperModule extends SimpleModule {
public BusinessCategoryParentsOnlyMapperModule() {
super("BusinessCategoryParentsOnlyMapperModule",
new Version(1, 0, 0, "SNAPSHOT", "", ""));
}
public void setupModule(SetupContext context) {
context.setMixInAnnotations(
BusinessCategory.class,
BusinessCategoryParentsOnlyMixIn.class);
}
}
My current solution works, it just doesn't feel very clean.
"categories" : [ {
"name" : "Personal Driver",
"parentCategories" : [ {
"name" : "Transportation",
"parentCategories" : [ ]
} ]
}
Oh yes, I'm using:
spring-boot 1.2.7
spring-framework: 4.1.8
jackson 2.6.3
Others listed here: http://docs.spring.io/spring-boot/docs/1.2.7.RELEASE/reference/html/appendix-dependency-versions.html
In the end, the only process that met my needs was to create a set of view objects which exposed only the fields I wanted to expose. In the grand scheme of things, it only added a small amount of seemingly unnecessary code to the project and made the flow of data easier to understand.

HttpServletRequest - Get Literal Path

I have a method marked with Spring's #RequestMapping that includes an HttpServletRequest method parameter.
If I print out the results of a call to "request.getServletPath()" when the path is, say, "/things/{thingId}", I will get "/things/2489sdfjk43298f," where the {thingId} path parameter has been replaced with the actual value.
I want to print out the literal request path "/things/{thingId}"; I.e. with the curly-braced, un-replaced path parameter "{thingId}."
Is this possible in any way?
Edit: After looking at Sotirios's second comment below, I realize I may be looking at the problem backward. Here's what I'm actually trying to do...
I am trying to making a single endpoint under "/**" that gets the path from the HttpServletRequest, which I use to look up a value in an enum. This enum has several fields, one of which is obviously the aforementioned path, but another is the path of a target JSP file. I then put this path into a ModelAndView object and return it to display the page.
This was going just fine until I hit the first endpoint with a path parameter, because I obviously can't place the value "/things/2489sdfjk43298f" into the enum, because that will only match for that one specific thing with that one specific ID.
So perhaps the actual question would be: How would I do that look-up when parts of the path will change due to path parameters? Is there some sort of wildcard-containing String format I can use?
I guess this is turning into more of a enum-lookup/String-matching question. My bad.
Edit 2: Shortened example of the enum thing I'm talking about:
public enum JspEndpointType {
HOME("/home", "jsp/home");
private static final Map<String, String> pathMap;
private String requestPath;
private String jspPath;
static {
pathMap = new HashMap<>();
for (JspEndpointType jspEndpointType : JspEndpointType.values()) {
pathMap.put(jspEndpointType.getRequestPath(), jspEndpointType.getJspPath());
}
}
private JspEndpointValue(String requestPath, String jspPath) {
this.requestPath = requestPath;
this.jspPath = jspPath;
}
public String getRequestPath() {
return requestPath;
}
public String getJspPath() {
return jspPath;
}
public static String getByRequestPath(String requestPath) {
return pathMap.get(requestPath);
}
}
Shortened example of my endpoint:
#RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView showPage(HttpServletRequest request) {
return new ModelAndView(JspEndpointType.getByRequestPath(request.getServletPath()));
}
So things essentially boil down to trying to add to the enum a value like this:
THINGS("/things/{thingId}", "jsp/things/whatever")
..and then being able to pass in the path "/things/2489sdfjk43298f" and get back "/jsp/things/whatever."
Edit 3: I found this StackoverFlow question which directed me to Spring's UriComponentsBuilder, specifically the "fromPath" method. However, that seems to be the reverse of what I'm trying to do...
You may look for the #RequestMapping annotation on your own, using reflection.

Return literal JSON strings in spring mvc #ResponseBody

I am storing objects in my database as JSON strings. I want to make a REST service that exposes these strings. When I write my methods however, the strings I get back have their quotes escaped. For example, I have included a method that returns a String,
#RequestMapping(value = "test", method = RequestMethod.GET)
public #ResponseBody
String getTest() {
return "{\"a\":1, \"b\":\"foo\"}";
}
but when I call this method in the browser I get a back "{\"a\":1, \"b\":\"foo\"}" when what I really want to happen is {"a": 1, "b": "foo"}. I think "String" as the return type is likely the problem, but what else can I do? A wrapper class does the same thing:
{
"value" : "{\"a\":1, \"b\":\"foo\"}"
}
I could serialize it and then return the object, but that seems a bit ridiculous.
Here is a possibly the relevant portion of my configuration file:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
converters.add(mappingJacksonHttpMessageConverter());
}
#Bean
MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter() {
MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
mappingJacksonHttpMessageConverter.setObjectMapper(objectMapper);
mappingJacksonHttpMessageConverter.setPrettyPrint(true);
return mappingJacksonHttpMessageConverter;
}
Thanks
EDIT: as was suggested below, it seems the string is being double encoded. Commenting out the 2 classes in my configuration fixes this issue. However, I still have other places where I want to return Objects and would like to keep those running through that common serializing bean that I know where to configure. So I see my options as:
a) Do all the serializing myself. All methods return Strings, and those that are already JSON return themselves, and those that are objects all return JSONUtil.toJson(object). I don't love this approach, but I know it will work.
b) Use a wrapper class that looks kind of like:
public static class Wrapper {
#JsonRawValue
private final String value;
}
This leads to an awkward "value" at the front though that has no real meaning.
Basically what I want is #JsonRawValue, but to have it work on RequestMapping methods instead of properties.
Thoughts? Opinions? Other suggestions?
This works with Jackson 2 (at least):
#Controller
public class YourController {
#RequestMapping(..)
public #ResponseBody Json get() {
return new Json("{ \"attr\" : \"value\" }");
}
}
class Json {
private final String value;
public Json(String value) {
this.value = value;
}
#JsonValue
#JsonRawValue
public String value() {
return value;
}
}
Not particularly pretty but works. I only wish Spring supported this:
#RequestMapping(..)
public #JsonRawValue #ResponseBody String get() {
// ...
}
I guess what you want is producing a response with content-type application/json. In your case, when you have the json-data as a raw string, do the following:
In your controller add produces="application/json" to your #RequestMapping attribute:
#RequestMapping(value = "test", method = RequestMethod.GET, produces="application/json")
public #ResponseBody
String getTest() {
return "{\"a\":1, \"b\":\"foo\"}";
}
Then you have to configure the StringHttpMessageConverter to accept the application/json media-type.
With Java-config:
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(
Charset.forName("UTF-8"));
stringConverter.setSupportedMediaTypes(Arrays.asList( //
MediaType.TEXT_PLAIN, //
MediaType.TEXT_HTML, //
MediaType.APPLICATION_JSON));
converters.add(stringConverter);
}
With XML-config:
<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<array>
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json; charset=UTF-8" />
</bean>
</array>
</property>
</bean>
I used this:
#RequestMapping(..)
#ResponseBody
public JsonNode myGetRequest(){
...
//rawJsonString is the raw Json that we want to proxy back to the client
return objectMapper.readTree(rawJsonString);
}
And the Jackson converter knew how to transform the JsonNode into plain Json.
If you want to convert JSON String to JSON object in your browser, keep string convertor before Jackson convertor.
Follow this link for complete example. It works with custom converter configuration plus spring validation.
It Works
converters.add(stringConverter());
converters.add(mappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
It Doesn't
converters.add(mappingJackson2HttpMessageConverter());
converters.add(stringConverter());
super.configureMessageConverters(converters);
In my case, I wanted the response type to be determined by a request parameter, so had to specify the content type in the code, e.g.:
#RequestMapping("/myurl")
public void radiusSearch(#RequestParam responseType, HttpServletResponse response) throws IOException {
String jsonResponse = makeSomeJson();
response.setContentType(responseType);
try {
response.getOutputStream().write(jsonResponse.getBytes());
} finally {
response.getOutputStream().close();
}
}
Today we had the same issue and solved it with multiple converters. Now every String will treated as a string and every other Object will get serialised by Jackson. This allows to serialise manually (by returning String) or automatically (by returning something else) in Spring controllers.
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(stringConverter());
converters.add(mappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
}
#Bean
public StringHttpMessageConverter stringConverter() {
final StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(UTF_8);
stringConverter.setSupportedMediaTypes(Arrays.asList(
MediaType.TEXT_PLAIN,
MediaType.TEXT_HTML,
MediaType.APPLICATION_JSON));
return stringConverter;
}
#Bean
public GenericHttpMessageConverter<Object> mappingJackson2HttpMessageConverter() {
final ObjectMapper objectMapper = objectMapperBuilder().build();
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(objectMapper);
return converter;
}
The \" means the character " is being escaped, which is standard. If it's being printed like that, you're probably double-serializing the object.
I know this is an old question, but I was just dealing with the opposite problem myself (I was returning a String and WANTED it to get converted to JSON). In your case, it sounds like you simply want to have your String treated as a plain string and not have any sort of JSON conversion done on it as you already have JSON.
So in your case you don't want to use the MappingJacksonHttpMessageConverter (or the MappingJackson2HttpMessageConverter if you're now using Jackson2). You want no conversions done at all, and that converter converts Java objects to/from JSON. So instead you should just use the plain StringHttpMessageConverter. You can do that by changing your setup method like this:
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new StringHttpMessageConverter());
}
This converter is applicable to */* types (the document is incorrect which says text/*, I found out the hard way in the debugger). So whether your content type is application/json or not, either way Spring won't mess with your Strings if you use this converter.
The solution to your problem is, this works perfectly without changing any configurations
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;
JsonNode getTest() {
return JsonLoader.fromString("{\"a\":1, \"b\":\"foo\"}");
}

How to send serialized object to a servlet using Apache HttpClient

I have a Main() class where I serialize an object of a class called Names. I am using Apache HttpClient's HttpPost() to call a servlet.
public static void main(String[] args) {
Names names = new Names();
names.setName("ABC");
names.setPlace("Bangalore");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Name.txt"));
out.writeObject(names);
out.close();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://localhost:6080/HttpClientGson/FirstHttpPostServlet");
Now, how do I send the ObjectOutputStream object? I wrote the following line
httppost.setEntity(out)
But setEntity() can only take objects of HttpEntity type. Is there any other method of HttpClient that I can use to send serialized object?
You could SerializableEntity class shipped with HttpClient
httpost.setEntity(new SerializableEntity(mySerializableObj, false));
Please note, though, that binary object serialization should be used only when absolutely required. Other serialization formats such as XML or JSON should generally be preferred.
You can use XStream to serialize an object to XML/JSON.
http://x-stream.github.io/
and then to pass it.

Resources