org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0xdf - json

I'm using the jackson framework for marshaling and unmarshalling data between JSON and Java. Everything works well, as long the input doesn't contain any characters like:
ö
ä
ü
Ö
Ä
Ü
ß
For input data I tried:
String jsonData = "{\"id\":1,\"street\":\"Straße\",\"number\":\"1c\",\"zipCode\":1111,\"city\":\"MyCity\"}";
as well as:
String jsonData = "{\"id\":1,\"street\":\"Stra\u00DFe\",\"number\":\"1c\",\"zipCode\":1111,\"city\":\"MyCity\"}";
and all the time I get the same exception.
The mapping from json data to java entity object is done via:
/*
* Convert stream to data entity
*/
ObjectMapper m = new ObjectMapper();
T entity = (T) m.readValue(stringToStream(jsonData), readableClass);
I also perform a json data validation which works like expected, also with the above chars.
How should such data be handled?
UPDATE
These are the important parts of the MessageBodyReader class
#Override
public T readFrom(Class<T> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
final String jsonData = getStringFromInputStream(entityStream);
System.out.println(jsonData);
InputStream isSchema = new FileInputStream(jsonSchemaFile);
String jsonSchema = getStringFromInputStream(isSchema);
/*
* Perform JSON data validation against schema
*/
validateJsonData(jsonSchema, jsonData);
/*
* Convert stream to data entity
*/
ObjectMapper m = new ObjectMapper();
T entity = (T) m.readValue(stringToStream(jsonData), readableClass);
return entity;
}
/**
* Validate the given JSON data against the given JSON schema
*
* #param jsonSchema
* as String
* #param jsonData
* as String
* #throws MessageBodyReaderValidationException
* in case of an error during validation process
*/
private void validateJsonData(final String jsonSchema, final String jsonData)
throws MessageBodyReaderValidationException {
try {
final JsonNode d = JsonLoader.fromString(jsonData);
final JsonNode s = JsonLoader.fromString(jsonSchema);
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonValidator v = factory.getValidator();
ProcessingReport report = v.validate(s, d);
System.out.println(report);
if (!report.toString().contains("success")) {
throw new MessageBodyReaderValidationException(
report.toString());
}
} catch (IOException e) {
throw new MessageBodyReaderValidationException(
"Failed to validate json data", e);
} catch (ProcessingException e) {
throw new MessageBodyReaderValidationException(
"Failed to validate json data", e);
}
}
/**
* Taken from <a href=
* "http://www.mkyong.com/java/how-to-convert-inputstream-to-string-in-java/"
* >www.mkyong.com</a>
*
* #param is
* {#link InputStream}
* #return Stream content as String
*/
private String getStringFromInputStream(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
private InputStream stringToStream(final String str) {
return new ByteArrayInputStream(str.getBytes());
}

JSON specification states, that only valid encodings are UTF-8, UTF-16 and UTF-32. No other encodings (like Latin-1) can be used. Your stringToStream implementation is not setting the encoding explicitly, so system default is used. That is how you got non-utf stream. On the next step Jakson is trying to parse the stream using one of UTF encodings (it has detection algorithm built in) and fails. Try setting an explicit encoding:
new ByteArrayInputStream(str.getBytes("UTF-8"));

You already got an answer, but one obvious question here is this: why are you converting from a String to a stream? That is unnecessary and wasteful thing to do -- so just pass the String as-is. This will also remove the problem; Strings do not have encoding per se (that is: there is just a single in-memory representation and no conversions are needed).

Related

How to access nested JSON with array in firebase

I want to access a JSON of this structure in firebase
The structure
{
"questions":{
"English":{
"English_2002":[
{
"correct_ans":"A",
"OptionA":"a coder",
"OptionB":"a hacker",
"OptionC":"a writer",
"OptionD":"a programmer",
"Question":"Who build software"
},
{},
{}
],
"English_2003":[],
}
}
}
I want this structure. In the subject structure, other subjects will come after I exhaust 9 years of English.
My confusion is how to logically get each subject since firebase will only accept the root name questions.
Please I may sound dumb, but I have a very long questions thread almost 55000 lines. Because firebase accept one JSON tree.
Sorry i wasn't very clear i was asking from the stack phone app:
I have a question json tag of the structure above; my question is how will i be able to access the object subject like "english":{
// then accessing the first english array "english":[]
//since am now using firebase.
}
initially each array was individual json file, i have to recreate them into one for firebase sake. this is how i was parsing it then.
public class QuestionParser {
Context context;
public QuestionParser(Context c) {
this.context = c;
}
public ArrayList<Question> getJsonFromUrl(String url, String arrayName)
{
ArrayList<Question> arrayofQuestion = new ArrayList<>();
return arrayofQuestion;
}
// Processing question from JSon file in res > raw folder
public ArrayList<Question> parseQuestionJson(int rawJsonFileId, String arrayName) {
ArrayList<Question> questionList = new ArrayList<>();
String jsonstr = null;
try {
InputStream in = context.getResources().openRawResource(rawJsonFileId);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
jsonstr = sb.toString();
Log.d("REEEEADDD" + this.toString(), jsonstr);
//System.out.println(jsonstr);
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(jsonstr)) {
return null;
}
try {
JSONObject jsonObject = new JSONObject(jsonstr);
JSONArray jsonArray = jsonObject.getJSONArray(arrayName);
JSONObject jobject;
for (int i = 0; i < jsonArray.length(); i++) {
// TEST
jobject = jsonArray.getJSONObject(i);
String ans = jobject.getString("correct_answer");
String graphic_name = jobject.getString("question_image");
String optionA = jobject.getString("optiona");
String optionB = jobject.getString("optionb");
String optionC = jobject.getString("optionc");
String optionD = jobject.getString("optiond");
String questionNo = jobject.getString("question_number");
String question = jobject.getString("question");
questionList.add(new Question(questionNo, graphic_name, question, optionA, optionB, optionC, optionD, ans));
Log.d("DDD" + this.toString(), String.valueOf(questionList.get(i)));
}
Log.i("ONE QUESTION", questionList.get(50).getQuestion());
} catch (Exception e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
return questionList;
}
}
So how can i parse it from firebase because initially, if a student chooses question and year i passes those value as parameter and use them for parsing. but in firebase now i have access to only root firebase name in the get reference e method
To access for example "correct_ans":"A" you would query your firebase like so:
your.firebase.domain/questions/English/English_2002/0/correct_ans
Notice that each level in the json object is represented by a / and the key you want to access whereas in case of an array you simple add the array index. JSON's simple structure also allows simple REST like access

Apache Flink : Window Function on AllWindowed Stream - Combining Kafka Topics

I am trying to combine two kafka topics using the a single kafka consumer on a list of topics, further convert the json string in the stream to POJO. Then, join them via keyBy ( On event time field ) and to merge them as a single fat json, I was planning to use a window stream and apply a window function on the window stream. The assumption is that Topic-A & Topic-B can be joined on Event Time and only one pair ( Topic A ( JSON ) , Topic B (JSON ) will be present with the same eventTime. Hence was planning to use a coutWindow(2) post keyBy on eventTime.
I have couple of questions for the same;
Is the approach fine for merging topics and creating a single JSON?
The window function on All Window stream doesnt seem to work fine; Any pointers will be greatly appreciated.
Code Snippet :
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
logger.info("Flink Stream Window Charger has started");
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "127.0.0.1:1030");
properties.setProperty("zookeeper.connect", "127.0.0.1:2181/service-kafka");
properties.setProperty("group.id", "group-0011");
properties.setProperty("auto.offset.reset", "smallest");
List < String > names = new ArrayList < > ();
names.add("Topic-A");
names.add("Topic-B");
DataStream < String > stream = env.addSource(new FlinkKafkaConsumer08 < > (names, new SimpleStringSchema(), properties));
DataStream < TopicPojo > pojo = stream.map(new Deserializer()).keyBy((eventTime) -> TopicPojo.getEventTime());
List < String > where = new ArrayList < String > ();
AllWindowedStream < String, GlobalWindow > data_window = pojo.flatMap(new Tokenizer()).countWindowAll(2);
DataStream < String > data_charging = data_window.apply(new MyWindowFunction());
data_charging.addSink(new SinkFunction < String > () {
public void invoke(String value) throws Exception {
// Yet to be implemented - Merge two POJO into one
}
});
try
{
env.execute();
} catch (Exception e)
{
return;
}
}
}
class Tokenizer implements FlatMapFunction < TopicPojo, String > {
private static final long serialVersionUID = 1 L;
#Override
public void flatMap(TopicPojo value, Collector < String > out) throws Exception {
ObjectMapper mapper = new ObjectMapper();
out.collect(mapper.writeValueAsString(value));
}
}
class MyWindowFunction implements WindowFunction < TopicPojo, String, String, GlobalWindow > {
#Override
public void apply(String key, GlobalWindow window, Iterable < TopicPojo > arg2, Collector < String > out)
throws Exception {
int count = 0;
for (TopicPojo in : arg2) {
count++;
}
// Test Result - TO be modified
out.collect("Window: " + window + "count: " + count);
}
}
class Deserializer implements MapFunction < String, TopicPojo > {
private static final long serialVersionUID = 1 L;
#Override
public TopicPojo map(String value) throws IOException {
// TODO Auto-generated method stub
ObjectMapper mapper = new ObjectMapper();
TopicPojo obj = null;
try {
System.out.println(value);
obj = mapper.readValue(value, TopicPojo.class);
} catch (JsonParseException e) {
// TODO Auto-generated catch block
throw new IOException("Failed to deserialize JSON object.");
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
throw new IOException("Failed to deserialize JSON object.");
} catch (IOException e) {
// TODO Auto-generated catch block
throw new IOException("Failed to deserialize JSON object.");
}
return obj;
}
}
I am getting -
The method apply(AllWindowFunction) in the type AllWindowedStream is not applicable for the arguments (MyWindowFunction) error.
An AllWindowedStream is a non-keyed stream, and so the apply method for AllWindowedStreams doesn't have a key parameter. Since you are windowing a keyed stream, your data_window should be a KeyedStream.

Encoding collection to json array in jsr 356

I am learning websockets and my webapp is using jsr 356 library. I followed the tutorials and I can encode/decode POJOs, however I can't find examples on how to serialize either arrays or collections to JSON.
This is what I am doing to encode my data:
#Override
public String encode(ScanPlus scan) throws EncodeException {
JsonObject jsonObject = createJsonObject(scan);
return jsonObject.toString();
}
private JsonObject createJsonObject(ScanPlus scan) {
JsonObject jsonObject = Json.createObjectBuilder()
.add("scan", scan.getCode())
.add("creationdate", String.valueOf(scan.getCreationDate()))
.add("username", scan.getUserName())
.build();
return jsonObject;
}
public String encode(ArrayList<ScanPlus> scans) throws EncodeException {
JsonArrayBuilder jsonArray = Json.createArrayBuilder();
for (ScanPlus scan : scans) {
JsonObject jsonObject = createJsonObject(scan);
jsonArray.add(jsonObject);
}
return jsonArray.toString();
}
This is how I send the data to the encoder:
#OnOpen
public void onOpen(Session session, #PathParam("username") String username) {
...
session.getBasicRemote().sendObject(scans);
}
And this is the exception I am getting:
javax.websocket.EncodeException: No encoder specified for object of class [class java.util.ArrayList]
Could anyone give me a hint on how to do it?
thanks
You need to create Encoder<ArrayList<ScanPlus>>; Encoder<ScanPlus> is not enough..

java restful web services retrieving post data

I am getting a JSON object POST request from android volley.I am trying to read the json using the following code.
#POST
#Path("/driver/insertTripLog")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_PLAIN)
public String insertTripLog(InputStream incomingData) throws Exception
{
StringBuilder sb = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incomingData));
String line = null;
while ((line = in.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
System.out.println("Error Parsing: - ");
}
String data=sb.toString();
System.out.println("Data Received: " +data );
return data;
}
The output i am getting json object but the special characters are encoded with %XX format.
Sample Output:
json=%5B%7B%22name%22%3A%22value%22%7D%5D
how to read properly post json data sent from volley.
Use the URLDecoder class to handle the percent encoded content which you are seeing:
String data = sb.toString();
data = java.net.URLDecoder.decode(data, "UTF-8");
Output:
json=[{"name":"value"}]

Getting issue while parsing json using jackson

i am using jackson to parse data i am using following code to parse json
public Map<String, Object> savePreference(#RequestBody Map map) throws IOException{
List preferenceDetails = (List) map.get("data");
int preferenceIndex = 0;
while(preferenceIndex < preferenceDetails.size()){
final ObjectMapper mapper = new ObjectMapper();
System.out.println(preferenceDetails.get(preferenceIndex));
mapper.readValue(preferenceDetails.get(preferenceIndex).toString(), Preference.class);
preferenceIndex++;
}
return null;
}
i am sending json from client side like this
{"data":[
{
"preferenceType":"Travelling"
},
{
"preferenceType":"Shopping"
}
]
}
but above code throws exception when i called
mapper.readValue(preferenceDetails.get(preferenceIndex).toString(), Preference.class);
exception is
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('p' (code 112)): was expecting double-quote to start field name
i am printing preference details in while loop
{preferenceType=Travelling}
You do not need to parse line by line. Using objects directly will be much more easier. Here is a test case which demonstrates how to parse your json to a object directly.
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import java.util.Collection;
public class JacksonTest {
#Test
public void testName() throws Exception {
final String test = "{\"data\":[\n" +
" {\n" +
" \"preferenceType\":\"Travelling\"\n" +
" },\n" +
" {\n" +
" \"preferenceType\":\"Shopping\"\n" +
" }\n" +
" ]\n" +
"}";
final ObjectMapper objectMapper = new ObjectMapper();
final Data data = objectMapper.readValue(test, Data.class);
Assert.assertNotNull(data);
Assert.assertEquals(2, data.getData().size());
}
static class Data {
private Collection<PreferenceType> data;
public Collection<PreferenceType> getData() {
return data;
}
public void setData(Collection<PreferenceType> data) {
this.data = data;
}
}
static class PreferenceType {
private String preferenceType;
public String getPreferenceType() {
return preferenceType;
}
public void setPreferenceType(String preferenceType) {
this.preferenceType = preferenceType;
}
}
}
After that you can build your own map how ever you want. But your framework may be able to handle this kind of request. You do not need to parse it manually. You should try getting Data object directly, instead of getting your body as Map.
Update
Try something like this. But first define Data class properly ( at least not as an inner class).
public Map<String, Object> savePreference(#RequestBody Data data) throws IOException{
...
}
Update 2
And also your map already has your object PreferenceDetail. It may already handle the json and map it as object. Please debug and check if your map.get("data") returns List<PreferenceDetail> or not. If it returns List there is no more work is needed to parse json using jackson. You can simply do something like this.
public Map<String, Object> savePreference(#RequestBody Map map) throws IOException{
List<PreferenceDetail> preferenceDetails = (List) map.get("data");
for (PreferenceDetail preferenceDetail : preferenceDetails) {
System.out.println(preferenceDetail.getPreferenceType());
}
return null;
}
I solved my problem by using jackson object mapper.
public Map<String, Object> savePreference(#RequestBody Map map) throws IOException{
log.debug("saving preferences");
if(preferenceService.getPreferencesByUser() != null && preferenceService.getPreferencesByUser().size() != 0)
return ResponseHandler.generateResponse(configProp.getProperty("user.preference.exist"), HttpStatus.ACCEPTED, true, null);
final ObjectMapper mapper = new ObjectMapper();
List preferenceDetails = (List) map.get("data");
int preferenceIndex = 0;
while(preferenceIndex < preferenceDetails.size()){
preferenceService.savePreference(mapper.readValue(mapper.writeValueAsString(preferenceDetails.get(preferenceIndex)), Preference.class));
preferenceIndex++;
}
return ResponseHandler.generateResponse(configProp.getProperty("preference.added"), HttpStatus.ACCEPTED, true, null);
}