Most Efficient way to convert jdbctemple result to json? - json

One Way is to convert the List< Map < String, Object>> into List(object); Given Below
List<Map<String, Object>> ls = jdbcTemplate.queryForList(query);
List<Users> ls_o = new ArrayList<>(ls_o);
for (Map<String, Object> row : ls) {
ls_o.add(row);
}
return new ResponseEntity<List<User>>(ls_o, HttpStatus.OK);
Is there any effiecient way to directly convert the jdbcTemplate result into json object?

If you are using Maven as you build script. Add following dependency
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.5</version>
</dependency>
Modify Code as shown below
private final ObjectMapper mapper = new ObjectMapper();
public ResponseEntity myMethod(){
List<Map<String, Object>> ls = jdbcTemplate.queryForList(query);
final String str = mapper.writeValueAsString(ls);
return new ResponseEntity<List<User>>(str, HttpStatus.OK);
}
However if you are using Spring 4+ MVC, I would recommend you to use #RestController
Which does most of the job for you here is an example for you, here is simple example
#RestController
class MyTestClass{
#RequestMapping("/myMethod")
public List<Map<String, Object>> myMethod(){
return jdbcTemplate.queryForList(query);
}
}
Note: In Both Above cases you need to convert The Object class to a Exact class to work.

Related

No converter found for return value of type: class org.json.JSONObject when returning JSONObject

I am migrating my project from springMVC to springboot. One of the controller has an API returning in this way.
I am trying to return JSONObject,
Here is my interface:
public class myController{
#RequestMapping(value = "/api", method = { RequestMethod.GET,
RequestMethod.POST })
public #ResponseBody JSONObject myfunction(HttpServletRequest request,
HttpServletResponse response);
}
I get the the following error:
No converter found for return value of type: class org.json.JSONObject
I have added jackson dependencies. I want to return JSONObject only. I have seen solutions but they are advising me to convert to a string. But i cannot do that as this could affect when i am returning to the front end(Which has been written already in jsp and jQuery and is expecting a JSONObject.)
How do i solve this?
Thanks.
You can use ObjectNode of Jackson library to keep JSONObject structure refer link. For that you have to autowire ObjectMapper in your service
public class myController{
#Autowired
private ObjectMapper jacksonObjectMapper;
#GetMapping
public ObjectNode sayJSONObject() {
ObjectNode objectNode = jacksonObjectMapper.createObjectNode();
objectNode.put("key", "value");
return objectNode;
}
}

spring mvc output in json format

I am very new for spring mvc and java. i want to return a json data instead of string
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public String getFoosAsJsonFromREST() {
return "{\"name\":\"MyNode\", \"width\":200, \"height\":100}";
}
actual output:
"{\"name\":\"MyNode\", \"width\":200, \"height\":100}"
output i want:
{"name":"MyNode", "width":200, "height":100}
i followed the link but i still can't get literal json output
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public JsonNode getFoosAsJsonFromREST() {
String everything = "{\"a\":2,\"b\":\"astring\",\"c\":6}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(everything);
return node;
}
output
{
"result": false,
"message": "Unexpected end-of-String when base64 content\n at [Source: N/A; line: -1, column: -1]"
}
You're nearly there :)
JSON is just an object format so you must return an object with key:value pairs.
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public MyJSONRespone getFoosAsJsonFromREST() {
MyJSONRespone myResponse = new MyJSONRespone();
myResponse.setName("MyNode");
myResponse.setWidth(200);
myResponse.setHeight(100);
return myResponse;
}
class MyJSONRespone{
private String name;
private Integer width;
private Integer Height;
//setters and getters
}
Also make sure you have the correct dependency in your POM if you are using Maven:
<!-- Jackson/JSON START -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.2</version>
</dependency>
<!-- Jackson/JSON END -->
Sure you can return json output without your own class. First approach same as yours try this one https://stackoverflow.com/a/64482663/10353679
#RequestMapping(value = "/ex/fooss", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public ResponseEntity<JsonNode> getDeneme() {
String everything = "{\"name\":\"MyNode\", \"width\":200, \"height\":100}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(everything);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return ResponseEntity.ok(node);
}
The example above should work
Second approach in your code just return node.toString() with produces = "application/json". json is just format. Client will probably just check the Content-Type which is application/json and if the format of json is correct, Client's parser will just parse it.
#RequestMapping(value = "/ex/foos", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public String getDeneme() {
String everything = "{\"a\":2,\"b\":\"astring\",\"c\":6}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(everything);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return node.toString();
}
IMPORTANT: node.toString(); might return NullPointerException since node can be null you should properly handle it.
And the other point is you should not create new ObjectMapper every time. You should inject ObjectMapper to this Controller class as a field and then just use injected objectMapper

How to include only specific properties when serializing with Jackson

I am trying to implement a universal method which serializes the given object to JSON, but only those properties which are passed in a collection. If possible I want to get this functionality without specifying #JsonFilter on the class. For this I am trying to use FilterExceptFilter from Jackson 2.4.1. Dependencies:
jackson-core-2.4.1.jar
jackson-databind-2.4.1.jar
jackson-annotations-2.4.0.jar
Here is what I have at the moment:
public static String serializeOnlyGivenFields(Object o,
Collection<String> fields) throws JsonProcessingException {
if ((fields == null) || fields.isEmpty()) return null;
Set<String> properties = new HashSet<String>(fields);
SimpleBeanPropertyFilter filter =
new SimpleBeanPropertyFilter.FilterExceptFilter(properties);
SimpleFilterProvider fProvider = new SimpleFilterProvider();
fProvider.addFilter("fieldFilter", filter);
fProvider.setDefaultFilter(filter);
ObjectMapper mapper = new ObjectMapper();
mapper.setFilters(fProvider);
String json = mapper.writeValueAsString(o);
return json;
}
However, the filter is never applied. It always serializes all properties.
Set<String> fields = new HashSet<String>(); fields.add("name");
String json = Serializer.serializeOnlyGivenFields(e, fields);
System.out.println(json);
{"name":"Test entity","description":"Test description"}
I have also tried to register the FilterProvider on the ObjectWriter, but same result:
String json = mapper.writer(fProvider).writeValueAsString(o);
What am I missing? Is there a nice way to achieve this with Jackson?
Based on http://www.cowtowncoder.com/blog/archives/2011/09/entry_461.html an alternate way to set up the filter is setting up a class that extends JacksonAnnotationIntrospector and overrides findFilterId. You can then specify to find your filter in the findFilterId. This could be made to be as robust if you want based on some other map or algorithm. Below is sample code. Not sure if the performance is better than the solution above but it seems to be simpler and probably more easily extensible. I was doing this for serializing CSV using Jackson. Any feedback is welcome!
public class JSON {
private static String FILTER_NAME = "fieldFilter";
public static String serializeOnlyGivenFields(Object o,
Collection<String> fields) throws JsonProcessingException {
if ((fields == null) || fields.isEmpty()) fields = new HashSet<String>();
Set<String> properties = new HashSet<String>(fields);
SimpleBeanPropertyFilter filter =
new SimpleBeanPropertyFilter.FilterExceptFilter(properties);
SimpleFilterProvider fProvider = new SimpleFilterProvider();
fProvider.addFilter(FILTER_NAME, filter);
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector( new AnnotationIntrospector() );
String json = mapper.writer(fProvider).writeValueAsString(o);
return json;
}
private static class AnnotationIntrospector extends JacksonAnnotationIntrospector {
#Override
public Object findFilterId(Annotated a) {
return FILTER_NAME;
}
}
}
One additional thing is that you have to indicate Java classes for which filter is to be used by #JsonFilter annotation:
#JsonFilter("fieldFilter")
public class MyType { }
and then it should apply.
I have found a solution based on Jackson: How to add custom property to the JSON without modifying the POJO. I override BeanSerializer#serializeFields to always use BeanSerializer#serializeFieldsFiltered instead. This way the filter is always applied.
Performance-wise not a very good solution, since an ObjectMapper has to be constructed at every method call. Feel free to post improvements or suggestions!
Module implementation:
public class FilteredModule extends SimpleModule {
private static final long serialVersionUID = 1L;
#Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new BeanSerializerModifier() {
#Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
if (serializer instanceof BeanSerializerBase) {
return new FilteredBeanSerializer(
(BeanSerializerBase) serializer);
}
return serializer;
}
});
}
private class FilteredBeanSerializer extends BeanSerializer {
public FilteredBeanSerializer(BeanSerializerBase source) {
super(source);
}
#Override
protected void serializeFields(Object arg0, JsonGenerator arg1,
SerializerProvider arg2) throws IOException,
JsonGenerationException {
super.serializeFieldsFiltered(arg0, arg1, arg2);
}
}
}
API method:
public static String serializeOnlyGivenFields(Object o,
Collection<String> fields) throws JsonProcessingException {
if ((fields == null) || fields.isEmpty()) fields = new HashSet<String>();
Set<String> properties = new HashSet<String>(fields);
SimpleBeanPropertyFilter filter =
new SimpleBeanPropertyFilter.FilterExceptFilter(properties);
SimpleFilterProvider fProvider = new SimpleFilterProvider();
fProvider.addFilter("fieldFilter", filter);
fProvider.setDefaultFilter(filter);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new FilteredModule());
String json = mapper.writer(fProvider).writeValueAsString(o);
return json;
}
Example
Entity e = new Entity("Test entity", "Test description");
Set<String> fields = new HashSet<String>(); fields.add("name");
String json = JSON.serializeOnlyGivenFields(e, fields);
System.out.println(json);
{"name":"Test entity"}
Benchmark: 1000 iterations on the same object
serializeOnlyGivenFields: 536 ms
serialize (reuses ObjectMapper): 23 ms

Better way to use json mixin with spring 4 controller

Is there a better way (possibly using annotations) to add a mixin to a spring controller.
Currently I am doing this:
#RequestMapping(value = "/accounts",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET,
params = "q")
#ResponseBody
#ResponseStatus(value = HttpStatus.OK)
public final String getAccountsViaQuery(#RequestParam("q") final String query)
throws JsonGenerationException, JsonMappingException, IOException {
final List<Account> matchingAccounts = accountService.findByAccountNameOrNumber(query);
ObjectMapper mapper = new ObjectMapper();
SerializationConfig serializationConfig = mapper.getSerializationConfig();
serializationConfig.addMixInAnnotations(Account.class, Account.SearchJsonMixin.class);
return mapper.writeValueAsString(matchingAccounts);
}
I would rather do this
#RequestMapping(value = "/accounts",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET,
params = "q")
#ResponseBody
#ResponseStatus(value = HttpStatus.OK)
public final List<Account> getAccountsViaQuery(#RequestParam("q") final String query)
throws JsonGenerationException, JsonMappingException, IOException {
return accountService.findByAccountNameOrNumber(query);
}
Looks much better to me, no boilerplate code and the return type is compiler checked.
Is is possible to use some sort of annotation on my controller to add a json mixin?
Wrote an annotation to solve this issue.
https://github.com/jackmatt2/JsonResponse

How to generate JSON schema from a JAXB annotated class?

I have a entity class looks like this.
#XmlRootElement
public class ImageSuffix {
#XmlAttribute
private boolean canRead;
#XmlAttribute
private boolean canWrite;
#XmlValue;
private String value;
}
And I'm using following dependency for JSON generation.
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.1.4</version>
</dependency>
When I tried with following code, (which referred from Generating JSON Schemas with Jackson)
#Path("/imageSuffix.jsd")
public class ImageSuffixJsdResource {
#GET
#Produces({MediaType.APPLICATION_JSON})
public String read() throws JsonMappingException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonSchema jsonSchema =
objectMapper.generateJsonSchema(ImageSuffix.class);
final String jsonSchemaString = jsonSchema.toString();
return jsonSchemaString;
}
}
Server complains with following error message
java.lang.IllegalArgumentException: Class com.googlecode.jinahya.test.ImageSuffix would not be serialized as a JSON object and therefore has no schema
at org.codehaus.jackson.map.ser.StdSerializerProvider.generateJsonSchema(StdSerializerProvider.java:299)
at org.codehaus.jackson.map.ObjectMapper.generateJsonSchema(ObjectMapper.java:2527)
at org.codehaus.jackson.map.ObjectMapper.generateJsonSchema(ObjectMapper.java:2513)
How can I fix this?
Have you tried configuring your ObjectMapper to include jaxb introspector? We use spring mvc3 for implementing REST services and use the same model objects to serialize into xml/json.
AnnotationIntrospector introspector =
new Pair(new JaxbAnnotationIntrospector(), new JacksonAnnotationIntrospector());
objectMapper.setAnnotationIntrospector(introspector);
objectMapper.generateJsonSchema(ImageSuffix.class);
EDIT: Here is the output I get from jackson:
{
"type" : "object",
"properties" : {
"canRead" : {
"type" : "boolean",
"required" : true
},
"canWrite" : {
"type" : "boolean",
"required" : true
},
"value" : {
"type" : "string"
}
}
}
Hope this helps!
The provided answer is a bit old and some of the things have been deprecated now. So try the following code with the latest Jackson and JAXB/Moxy annotated classes:
Approach-1
class JsonSchemaGenerator{
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = TypeFactory.defaultInstance();
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(typeFactory);
objectMapper.getDeserializationConfig().with(introspector);
objectMapper.getSerializationConfig().with(introspector);
//To force mapper to include JAXB annotated properties in Json schema
objectMapper.registerModule(new JaxbAnnotationModule());
SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
objectMapper.acceptJsonFormatVisitor(objectMapper.constructType(Customer.class), visitor);
JsonSchema inputSchema = visitor.finalSchema();
String schemaString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(inputSchema);
System.out.println(schemaString);
}
}
Approach -2 :
class JsonSchemaGenerator{
public static void main(String[] args) throws JsonProcessingException, ClassNotFoundException {
final ObjectMapper mapper = new ObjectMapper();
final TypeFactory typeFactory = TypeFactory.defaultInstance();
final AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(typeFactory);
mapper.getDeserializationConfig().with(introspector);
mapper.getSerializationConfig().with(introspector);
final JsonSchema jsonSchema = mapper.generateJsonSchema(Class.forName("com.jaxb.Customer"));
System.out.println(jsonSchema);
}
}