When I write a REST service in Java the framework I use (Spring, usually, but JEE is no different) will properly handle the serialization of your output for you. Sometimes though you already have the result available in JSON format inside a string and you would like to return it as it is. What can we do in such cases ?

Let’s say for example that we have a /hello/world service that is supposed to return the following static json: { "hello": "world" }. If we are working with Spring we could be tempted to write something like the following:

@RequestMapping( value = "/hello/world")
@Controller
public class HelloWorldController {
	@RequestMapping(value="", method = RequestMethod.GET, produces = MediaType.APPICATION_JSON_VALUE)
	public ResponseEntity<String> getHelloWorld() {
		String result = "{ 'hello': 'world' }";
		return new ResponseEntity<>(result, HttpStatus.OK);
	}
}

This doesn’t work though, because Spring will take the resulting string and serialize it in JSON. This means that instead of the expected

{ "hello": "world" }

the output of the service will be a JSON string containing the JSON value

"{ \"hello\": \"world\" }"

I found some suggestions in Internet, but none of them was satisfactory. For example some suggested to register a serializer for String, but that would mean that all String s would be considered as raw JSON values.

The solution I found is in fact surprisingly simple: wrap the String with the following class:

public class RawJson {
	private String payload;
	
	public RawJson(String payload) {
		this.payload = payload;
	}
	
	public static RawJson from(String payload) {
		return new RawJson(payload);
	}
	
	@JsonValue
	@JsonRawValue
	public String getPayload() {
		return this.payload;
	}
}

With this, our example service becomes

@RequestMapping( value = "/hello/world")
@Controller
public class HelloWorldController {
	@RequestMapping(value="", method = RequestMethod.GET, produces = MediaType.APPICATION_JSON_VALUE)
	public ResponseEntity<RawJson> getHelloWorld() {
		String result = "{ 'hello': 'world' }";
		return new ResponseEntity<>(RawJson.from(result), HttpStatus.OK);
	}
}

How does it work ? The trick is in the two annotations provided by Jackson. The first, @JsonValue, states that the result of the annotated method is to be used as the value of the seralization of the whole object.

On the other hand the annotation @JsonRawValue states that the annotated method returns a String which is already the serialized JSON of its value and doesn’t need to be serialized further.

If we put those two together, we get that the result of serializing the RawJson class is no more and no less that the return value of the getPayload method.