JSON parse error: Cannot deserialize value - json

I want to insert multiple data in postman but, I get this eror
"message": "JSON parse error: Cannot deserialize value of type com.test.rest.api.dtos.AnggotaDTO from Array value (token JsonToken.START_ARRAY); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type com.test.rest.api.dtos.AnggotaDTO from Array value (token JsonToken.START_ARRAY)\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 1]",
How i can resolve this eror ?
This is my request body, post in postman
[
{
anggotaNama: "AAA",
anggotaUsia: 16
},
{
anggotaNama: "BBB",
anggotaUsia: 17
},
{
anggotaNama: "CCC",
anggotaUsia: 18
}
]
This is my dtos.AnggotaDTO
package com.test.rest.api.dtos;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
public class AnggotaDTO {
private long anggotaId;
private String anggotaNama;
private int anggotaUsia;
}
This my controller
package com.test.rest.api.controllers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.test.rest.api.dtos.AnggotaDTO;
import com.test.rest.api.models.Anggota;
import com.test.rest.api.repositories.AnggotaRepository;
#RestController
#RequestMapping("/api")
public class AnggotaController {
#Autowired
private AnggotaRepository anggotaRepository;
ModelMapper modelMapper = new ModelMapper();
private Anggota convertAnggotaToEntity (AnggotaDTO anggotaDto) {
return modelMapper.map(anggotaDto, Anggota.class);
}
private AnggotaDTO convertAnggotaToDTO (Anggota anggota) {
return modelMapper.map(anggota, AnggotaDTO.class);
}
// API CREATE Anggota
#PostMapping("/anggota/create")
public Map<String, Object> createAnggota(#RequestBody AnggotaDTO anggotaDTO) {
Map<String, Object> mapResult = new HashMap<>();
Anggota anggota = convertAnggotaToEntity(anggotaDTO);
anggota.setAnggotaNama(anggotaDTO.getAnggotaNama());
anggota.setAnggotaUsia(anggotaDTO.getAnggotaUsia());
mapResult.put("message", "Craete Success");
mapResult.put("data", anggotaRepository.save(anggota));
return mapResult;
}
// API READ Anggota
#GetMapping("/anggota/get/findall")
public Map<String, Object> getAllAnggota () {
Map<String, Object> mapResult = new HashMap<>();
List<AnggotaDTO> listAnggotaDto = new ArrayList<>();
for (Anggota anggota : anggotaRepository.findAll()) {
AnggotaDTO anggotaDto = convertAnggotaToDTO(anggota);
listAnggotaDto.add(anggotaDto);
}
String message;
if (listAnggotaDto.isEmpty()) {
message = "Data is empty";
}
else {
message = "Show all data";
}
mapResult.put("message" , message);
mapResult.put("data", listAnggotaDto);
mapResult.put("total", listAnggotaDto.size());
return mapResult;
}
// API UPDATE Anggota
#PutMapping("/anggota/update")
public Map<String, Object> updateAnggota (#RequestParam(value="anggotaId") long anggotaId, #RequestBody AnggotaDTO anggotaDto) {
Map<String, Object> mapResult = new HashMap<>();
Anggota anggota = anggotaRepository.findById(anggotaId).orElse(null);
anggota.setAnggotaNama(anggotaDto.getAnggotaNama());
anggota.setAnggotaUsia(anggotaDto.getAnggotaUsia());
mapResult.put("message", "Update success");
mapResult.put("data", anggotaRepository.save(anggota));
return mapResult;
}
// API Delete Employee
#DeleteMapping("/anggota/delete/{anggotaId}")
public Map<String, Object> deleteAnggota (#PathVariable(value="anggotaId") long anggotaId) {
Map<String, Object> mapResult = new HashMap<>();
Anggota anggota = anggotaRepository.findById(anggotaId).orElse(null);
anggotaRepository.delete(anggota);
mapResult.put("message", "Delete Success");
return mapResult;
}
}

Related

spring boot kafka generic JSON templateSender

I am working with kafka and spring boot and I need to send JSON object to kafka, the point is that I am able to send an object as JSON configuring KafkaTemplate but just for this object.
package com.bankia.apimanager.config;
import com.bankia.apimanager.model.RequestDTO;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.support.serializer.JsonSerializer;
import java.util.HashMap;
import java.util.Map;
#Configuration
public class KafkaConfiguration {
#Value("${spring.kafka.bootstrap-servers}")
private String bootstrapServers;
#Bean
public Map<String, Object> producerConfigs() {
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
return props;
}
#Bean
public ProducerFactory<String, RequestDTO> producerFactory() {
return new DefaultKafkaProducerFactory<>(producerConfigs());
}
#Bean
public KafkaTemplate<String, RequestDTO> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
package com.bankia.apimanager.controller;
import com.bankia.apimanager.model.RequestDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/infrastructure")
public class InfraStructureRequestController {
private final static Logger LOG = LoggerFactory.getLogger( InfraStructureRequestController.class );
private static final String TOPIC = "test";
#Autowired
private KafkaTemplate<String, RequestDTO> sender;
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String postMessage(){
ListenableFuture<SendResult<String, RequestDTO>> future = sender.send(TOPIC, new RequestDTO("Hola","Paco"));
future.addCallback(new ListenableFutureCallback<SendResult<String, RequestDTO>>() {
#Override
public void onSuccess(SendResult<String, RequestDTO> result) {
LOG.info("Sent message with offset=[" + result.getRecordMetadata().offset() + "]");
}
#Override
public void onFailure(Throwable ex) {
LOG.error("Unable to send message due to : " + ex.getMessage());
}
});
return "OK";
}
}
but what about if now I want to send a new DTO object? do I have to declare a new KafkaTemplate<String,NEWOBJECT> and autowire each kafka template declared in configuration for each object? there is another way to be able to just declare one kafkaTemplate in which I can send any type of object and automatically will be serialized in JSON?
I think, you can specify a generic KafkaTemplate<String, Object> and set the producer value serializer to JsonSerializer like this:
#Configuration
public class KafkaConfiguration {
#Value("${spring.kafka.bootstrap-servers}")
private String bootstrapServers;
#Bean
public Map<String, Object> producerConfigs() {
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
return props;
}
#Bean
public ProducerFactory<String, Object> producerFactory() {
return new DefaultKafkaProducerFactory<>(producerConfigs());
}
#Bean
public KafkaTemplate<String, Object> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
Referring your code:
Value Serializer is correctly defined as JsonSerializer, which will convert objects of any type to JSON.
#Bean
public Map<String, Object> producerConfigs() {
Map<String, Object> props = new HashMap<>();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
return props;
}
Change <String, RequestDTO> to <String, Object> at every place in KafkaConfig & Controller.
Keep in mind that generics remain until compile time (type erasure)
only.
There are two scenario:
Scenario #1
If you want to use KafkaTemplate to send any type(as mentioned in your question) to kafka, so there is no need to declare your own KafkaTemplate bean because Spring boot did this for you in KafkaAutoConfiguration.
package org.springframework.boot.autoconfigure.kafka;
...
#Configuration(proxyBeanMethods = false)
#ConditionalOnClass(KafkaTemplate.class)
#EnableConfigurationProperties(KafkaProperties.class)
#Import({ KafkaAnnotationDrivenConfiguration.class, KafkaStreamsAnnotationDrivenConfiguration.class })
public class KafkaAutoConfiguration {
private final KafkaProperties properties;
public KafkaAutoConfiguration(KafkaProperties properties) {
this.properties = properties;
}
#Bean
#ConditionalOnMissingBean(KafkaTemplate.class)
public KafkaTemplate<?, ?> kafkaTemplate(ProducerFactory<Object, Object> kafkaProducerFactory,
ProducerListener<Object, Object> kafkaProducerListener,
ObjectProvider<RecordMessageConverter> messageConverter) {
KafkaTemplate<Object, Object> kafkaTemplate = new KafkaTemplate<>(kafkaProducerFactory);
messageConverter.ifUnique(kafkaTemplate::setMessageConverter);
kafkaTemplate.setProducerListener(kafkaProducerListener);
kafkaTemplate.setDefaultTopic(this.properties.getTemplate().getDefaultTopic());
return kafkaTemplate;
}
}
**Some Note**:
This config class has been annotated with #ConditionalOnClass(KafkaTemplate.class) that means: (from spring docs--->) #Conditional that only matches when the specified classes are on the classpath.
kafkaTemplate bean method is annotated with
#ConditionalOnMissingBean(KafkaTemplate.class) that means: (from spring docs ---->) #Conditional that only matches when no beans meeting the specified requirements are already contained in the BeanFactory.
Important! In pure java world, KafkaTemplate<?, ?> is not subtype of for example: KafkaTemplate<String, RequestDTO> so you can't to do this:
KafkaTemplate<?, ?> kf1 = ...;
KafkaTemplate<String, RequestDTO> kf2 = kf1; // Compile time error
because java parameterized types are invariant as mentioned in Effective Java third edition item 31. But is spring world that is ok and will be injected to your own service. You need only to specify your own generic type on your kafkaTemplate properties.
For example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
#Service
public class KafkaService {
#Autowired
private KafkaTemplate<Integer, String> kafkaTemplate1;
#Autowired
private KafkaTemplate<Integer, RequestDTO> KafkaTemplate2;
}
Scenario #2
If you need to restrict value type of kafka record then you need to specify your own kafka bean something like this:
#Configuration(proxyBeanMethods = false)
#ConditionalOnClass(KafkaTemplate.class)
#EnableConfigurationProperties(CorridorTracingConfiguration.class)
public class CorridorKafkaAutoConfiguration {
#Bean
#ConditionalOnMissingBean(KafkaTemplate.class)
public KafkaTemplate<?, AbstractMessage> kafkaTemplate(ProducerFactory<Object, AbstractMessage> kafkaProducerFactory,
ProducerListener<Object, AbstractMessage> kafkaProducerListener,
ObjectProvider<RecordMessageConverter> messageConverter) {
KafkaTemplate<Object, AbstractMessage> kafkaTemplate = new KafkaTemplate<>(kafkaProducerFactory);
messageConverter.ifUnique(kafkaTemplate::setMessageConverter);
kafkaTemplate.setProducerListener(kafkaProducerListener);
kafkaTemplate.setDefaultTopic(this.properties.getTemplate().getDefaultTopic());
return kafkaTemplate;
}
Now this can be injected only to
KafkaTemplate<String, AbstractMessage> kafkaTemplate, the key type can be anything else instead of String. But you can send any sub type of AbstractMessage to kafka via it.
An example usage:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
#Service
public class KafkaService {
#Autowired
private KafkaTemplate<String, AbstractMessage> kafkaTemplate;
public void makeTrx(TrxRequest trxRequest) {
kafkaTemplate.send("fraud-request", trxRequest.fromAccountNumber(), new FraudRequest(trxRequest));
}
}
#Accessors(chain = true)
#Getter
#Setter
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
public class FraudRequest extends AbstractMessage {
private float amount;
private String fromAccountNumber;
private String toAccountNumber;
...
}
To restrict the key of kafka message follow the same (above) way

How to get rest response that contains only certain object's json?

My goal is to get rest services working on spring boot web application.
But I am struggling with finding out how to tell response to include object's json only.
To be more precise, when calling http://localhost:8080/api/db/Keyboard/2, I intend to receive object with id 2 in json format and only:
{
"id": 2,
"language": "en"
}
But instead I get:
{
"status": 200,
"entity": {
"id": 2,
"language": "en"
},
"metadata": {},
"length": -1,
"allowedMethods": [],
"cookies": {},
"headers": {},
"actualEntity": {
"id": 2,
"language": "en"
},
"links": [],
"statusInfo": {
"reasonPhrase": "OK",
"statusCode": 200,
"family": "SUCCESSFUL"
},
"stringHeaders": {}
}
Clearly response contains too much info. Only the entity part is needed. How to reach intended result / adjust conditionally the response?
Below some files that might be relevant.
TestController.java:
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import main.domain.DaoApi;
import main.domain.Keyboard;
#RestController
public class TestController<T, K> {
private final static Map<String, Class<?>> tableClassMap = new HashMap<>();
#Autowired
private DaoApi<T, K> daoApi;
static {
addEntryTableClassMap(Keyboard.class);
}
#RequestMapping(value = "/api/db/{tableName}/{id}", method = RequestMethod.GET)
public Response getById(#PathVariable(value = "tableName") String tableName, #PathVariable(value = "id") Integer id) {
ResponseBuilder responseBuilder;
T entity = (T) daoApi.findById((Class<T>) getClassFromTableClassMap(tableName), id);
if (entity != null) {
responseBuilder = Response.ok(entity);
} else {
responseBuilder = Response.status(Status.NOT_FOUND);
}
return responseBuilder.build();
}
private static <C> void addEntryTableClassMap(Class<C> clazz) {
tableClassMap.put(clazz.getSimpleName().toLowerCase(), clazz);
}
private static <C> Class<C> getClassFromTableClassMap(String tableName) {
return (Class<C>) tableClassMap.get(tableName.toLowerCase());
}
}
Keyboard.java:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.transaction.annotation.Transactional;
#Transactional
#Entity
#Table(name = "keyboard")
public class Keyboard {
#Id
#Column(updatable = false)
private int id;
private String language;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
}
DaoApi.java:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class DaoApi<T, K> {
#Autowired
SessionFactory sessionFactory;
public T findById(Class<T> clazz, Integer id) {
Session session = sessionFactory.openSession();
T t = (T) session.get(clazz, id);
session.close();
return t;
}
}
Received comment that helped me to solution:
#RequestMapping(value = "/api/db/{tableName}/{id}", method = RequestMethod.GET)
public T getById(#PathVariable(value = "tableName") String tableName, #PathVariable(value = "id") Integer id) {
ResponseBuilder responseBuilder;
T entity = (T) daoApi.findById((Class<T>) getClassFromTableClassMap(tableName), id);
if (entity != null) {
responseBuilder = Response.ok(entity);
return (T) responseBuilder.build().getEntity();
} else {
responseBuilder = Response.status(Status.NOT_FOUND);
//some additional code here
return (T) responseBuilder.build();
}
}

How to parse recursive JSON object using JAXB

Below is my JSON, how to parse it using jaxb, note the depth and key of categories would change
{
"categories":{
"categoryHierarchy":[
{
"hierarchy":{
"SDG--1513417390":{
"SD-1501363638":{
"D-HS-MM4":{
"CL-HS-MM4-DEFAULT":{
"C-HS-MM4-MM0203":{
}
}
}
}
}
},
"precedence":1
}
]
}
}
After trying multiple things I was able to parse the recursive category structure.
package com.example;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pearson.aem.aemcore.pim.dto.com.example.Example;
class Parser{
private transient static ObjectMapper jsonMapper;
public static void main (String [] args) throws IOException
{
jsonMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String response = "{\"categoryHierarchy\":[{\"hierarchy\":{\"SDG--1513417390\":{\"SD-1501363638\":{\"D-HS-MM4\":{\"CL-HS-MM4-DEFAULT\":{\"C-HS-MM4-MM0203\":{}}}}}},\"precedence\":1}]}";
InputStream stream = new ByteArrayInputStream(response.getBytes());
Example ex = unmarshalJson(stream, Example.class);
System.out.println(ex.getCategoryHierarchy().get(0).getHierarchy1().getAdditionalProperties());
//System.out.println(ex.getCategoryHierarchy().get(0).getHierarchy().getAdditionalProperties().get("SDG--1513417390").keySet.iterator().next());
}
public static <T> T unmarshalJson(final InputStream result, final Class<T> declaredType) throws IOException
{
return (T) jsonMapper.readValue(result, declaredType);
}
}
----------------
package com.example;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlElement;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.pearson.aem.aemcore.pim.dto.CategoryElementDTO;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Example
{
#XmlElement(
name = "categoryHierarchy")
private List<CategoryHierarchy> categoryHierarchy;
#XmlElement(
name = "relatedCategories")
private Map<String, CategoryElementDTO> relatedCategories;
public List<CategoryHierarchy> getCategoryHierarchy()
{
return categoryHierarchy;
}
public void setCategoryHierarchy(List<CategoryHierarchy> categoryHierarchy)
{
this.categoryHierarchy = categoryHierarchy;
}
public Map<String, CategoryElementDTO> getRelatedCategories()
{
return relatedCategories;
}
public void setRelatedCategories(Map<String, CategoryElementDTO> relatedCategories)
{
this.relatedCategories = relatedCategories;
}
}
------------
package com.example;
public class CategoryHierarchy
{
private Hierarchy hierarchy;
private Integer precedence;
public Hierarchy getHierarchy()
{
return hierarchy;
}
public void setHierarchy(Hierarchy hierarchy)
{
this.hierarchy = hierarchy;
}
public Integer getPrecedence()
{
return precedence;
}
public void setPrecedence(Integer precedence)
{
this.precedence = precedence;
}
}
---------------
package com.example;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Hierarchy
{
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties()
{
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value)
{
this.additionalProperties.put(name, value);
}
}

JSON parse to populate listview Android Studio

I am pulling my hair out over this. After numerous tutorials, I thought I found the perfect one (7th to be exact. But after following the tutorial, I found out that JSONparse is deprecated. Can someone please give me a solution for this. I just want to read an array from the url and populate a listview.
The array is:
{ "lotInfo":[{"lot":"A","spaces":"198","rates":"3.25"},
{"lot":"B","spaces":"165","rates":"7.50"}]}
MainActivity.Java:
package com.example.sahan.wtf;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
public class MainActivity extends ListActivity {
private Context context;
private static String url = "http://192.168.0.199/get_info.php";
private static final String lot = "lot";
private static final String spaces = "spaces";
private static final String rates = "rates";
ArrayList<HashMap<String, String>> jsonlist = new ArrayList<HashMap<String, String>>();
ListView lv ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new ProgressTask(MainActivity.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
public ProgressTask(ListActivity activity) {
Log.i("1", "Called");
context = activity;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
ListAdapter adapter = new SimpleAdapter(context, jsonlist, R.layout.list_activity, new String[] { lot, spaces, rates }, new int[] { R.id.lot, R.id.spaces, R.id.rates });
setListAdapter(adapter);
lv = getListView();
}
protected Boolean doInBackground(final String... args) {
JSONParse jParser = new JSONParser();
JSONArray json = jParser.getJSONFromUrl(url);
for (int i = 0; i < json.length(); i++) {
try {
JSONObject c = json.getJSONObject(i);
String vlot = c.getString(lot);
String vspaces = c.getString(spaces);
String vrates = c.getString(rates);
HashMap<String, String> map = new HashMap<String, String>();
map.put(lot, vlot);
map.put(spaces, vspaces);
map.put(rates, vrates);
jsonlist.add(map);
} catch (JSONException e)
{
e.printStackTrace();
}
}
return null;
}
}
}
JSONParser.Java:
package com.example.sahan.wtf;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class JSONParser {
static InputStream is = null;
static JSONArray jarray = null;
static String json = "";
public JSONParser() {
}
public JSONArray getJSONFromUrl(String url) {
StringBuilder builder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} else {
Log.e("Error....", "Failed to download file");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
jarray = new JSONArray( builder.toString());
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
return array;
}
}
The error I get is:
Error:(74, 13) error: cannot find symbol class JSONParse
It seems that you have a typo, instead of:
JSONParse jParser = new JSONParser();
Should be:
JSONParser jParser = new JSONParser();

JSON marshaling of object arrays with JAXB

Using MOXy I'm trying to marshal a java class like this to JSON:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Request {
String method;
#XmlAnyElement(lax=true)
Object[] arguments;
}
I would expect something like:
{
"method": "test",
"arguments": ["a", "b"]
}
but the JSON output results to:
{
"method": "test",
"value": ["a", "b"]
}
Where is the value coming from?
If I put a #XmlElementWrapper over the arguments field, it gets even worse:
{
"method":"test",
"arguments":"a""value":["b"]
}
My JUnit TestCase looks like this:
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import org.junit.Test;
public class JsonRequestTest {
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class Request {
String method;
#XmlAnyElement(lax=true)
Object[] arguments;
} // InvocationRequest
#Test
public void testObjectArray() throws JAXBException {
System.setProperty(JAXBContext.class.getName(), "org.eclipse.persistence.jaxb.JAXBContextFactory");
Map<String, Object> props= new HashMap<String, Object>();
props.put("eclipselink.media-type", "application/json");
props.put("eclipselink.json.include-root", false);
JAXBContext ctx = JAXBContext.newInstance(new Class<?>[]{Request.class},props);
Marshaller m = ctx.createMarshaller();
StringWriter writer = new StringWriter();
Request req = new Request();
req.method="test";
req.arguments = new Object[]{"a","b"};
m.marshal(req, writer);
assertEquals("{\"method\":\"test\", \"arguments\":[\"a\",\"b\"]}", writer.toString());
}
} // class JsonRequestTest
Note: I'm the EclipseLink MOXy lead and a member of the JAXB (JSR-222) expert group.
TL:DR
You can set the following property to override the value key.
props.put(MarshallerProperties.JSON_VALUE_WRAPPER, "arguments");
Full Test Case
Below is the full working test case. In addition to setting the property I removed an extra space you had in your control document to get the test to pass.
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.junit.Test;
public class JsonRequestTest {
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class Request {
String method;
#XmlAnyElement(lax = true)
Object[] arguments;
} // InvocationRequest
#Test
public void testObjectArray() throws JAXBException {
System.setProperty(JAXBContext.class.getName(),
"org.eclipse.persistence.jaxb.JAXBContextFactory");
Map<String, Object> props = new HashMap<String, Object>();
props.put("eclipselink.media-type", "application/json");
props.put("eclipselink.json.include-root", false);
props.put(MarshallerProperties.JSON_VALUE_WRAPPER, "arguments");
JAXBContext ctx = JAXBContext.newInstance(
new Class<?>[] { Request.class }, props);
Marshaller m = ctx.createMarshaller();
StringWriter writer = new StringWriter();
Request req = new Request();
req.method = "test";
req.arguments = new Object[] { "a", "b" };
m.marshal(req, writer);
assertEquals("{\"method\":\"test\",\"arguments\":[\"a\",\"b\"]}",
writer.toString());
}
} // class JsonRequestTest
#XmlElementWrapper Issue
I have opened the following bug for the issue with #XmlElementWrapper:
http://bugs.eclipse.org/421977