How to Parse a incomplete JSON like string - java

I am reading some data via BLE from my peripheral device to my android app.
the app gets the data from BLE device in a JSON format. it all works fine, except in few cases when i get incomplete JSON string from BLE device (i have no control over that and i need to handle whatever i receive. Initially, i was getting a simple JSON array like
[wifi1, wifi2, wifi3, wifi4, wifi5]
So if get incomplete string i will handle JSON parse exception and use String Tokenizer and simply parse each token and get the wifi name
StringTokenizer tokens = new StringTokenizer(new String(bytes), ",");
int size = tokens.countTokens();
HashMap<String, Object> map;
for (int i = 0; i < size; i++) {
map = new HashMap<String, String>();
map.put("Wifi, tokens.nextToken().replace("\"", "").replace("]", "").replace("[", ""));
But now the JSON string has been changed and includes a lot of other information, this is the new JSON that i get
[{"ssid":"Wifi1","rssi":-50,"encrypt":"on"},{"ssid":"wifi2","rssi":-61,"encrypt":"on"},{"ssid":"wifi3","rssi":-81,"encrypt":"of
Now if i get incomplete JSON in this format (as above) i am not able to parse the wifi name and encrypt info using StringTokenizer (it's getting way complicated and ugly).
Do you have any idea on how to parse these wifi name and encrypt info from above string. Any suggestion will be of great help.

Thanks to #pskink and #Andreas for suggesting streaming JSON parser, i tried this and it works for me. Hopefully it will be helpful for someone else as well.
public void parseWifiJSON(byte[] bytes)
{
trackerWifiScanList = readJsonStream(bytes);
// do stuff with your list
}
public List<WifiScan> readJsonStream(byte[] bytes) {
JsonReader reader = new JsonReader(new StringReader(new String(bytes)));
List<WifiScan> resultList = null;
try {
resultList = readMessagesArray(reader);
reader.close();
} catch (IOException e) {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// Do nothing
}
}
}
return resultList;
}
public List<WifiScan> readMessagesArray(JsonReader reader) throws IOException {
ArrayList<WifiScan> messages = new ArrayList<WifiScan>();
try {
reader.beginArray();
while (reader.hasNext()) {
messages.add(readMessage(reader));
}
}catch (Exception e)
{
if (reader != null) {
try {
reader.endArray();
} catch (IOException ex) {
// Do nothing
}
}
}
return messages;
}
public WifiScan readMessage(JsonReader reader) throws IOException {
String wifissid ="";
int rssi = 0;
String encrypt="";
WifiScan wifInfo = new WifiScan();
try {
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("ssid")) {
wifissid = reader.nextString();
} else if (name.equals("rssi")) {
rssi = reader.nextInt();
} else if (name.equals("encrypt")) {
encrypt = reader.nextString();
} else {
reader.skipValue();
}
}
reader.endObject();
wifInfo.setSsid(wifissid);
wifInfo.setRssi(rssi);
wifInfo.setEncrypt(encrypt);
}catch (Exception e)
{
// JSON was not complete so just set a dummy object.
wifInfo.setSsid("");
wifInfo.setRssi(0);
wifInfo.setEncrypt("");
}
return wifInfo;
}

Related

Java Stream Corrupted error when iterating through Serialized file to deserialize

I initially created a file containing serialized data, and wanted to iterate through it and add the objects to a text file. However, I keep getting a StreamCorrupted error when I try doing so. Any suggestions on how to fix this? Thanks in advance.
The Method:
public static ImperialDrone retrieveDrone(String filename) {
try {
System.out.println(filename);
boolean cont = true;
ArrayList<ImperialDrone> list = new ArrayList<>();
ObjectInputStream Sin = new ObjectInputStream(new FileInputStream("C:\\Users\\13023\\eclipse-workspace\\Chunduru_HW6\\src\\chunduru\\STORAGE\\DStore"));
while(cont){
ImperialDrone I = null;
try {
I = (ImperialDrone) Sin.readObject();
} catch (EOFException E) {
E.printStackTrace();
}
if(I != null) {
list.add(I);
System.out.println("Added 1");
}
else {
cont = false;
}
}
Sin.close();
return list.get(0);
}
catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
return null;
}
The Error:
java.io.StreamCorruptedException: invalid type code: AC
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1764)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:509)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:467)
at Chunduru_HW6/chunduru.INTERFACES.DroneOperations.retrieveDrone(DroneOperations.java:49)
at Chunduru_HW6/chunduru.MAIN.Chunduru.main(Chunduru.java:26)
java.io.StreamCorruptedException: invalid type code: AC

try catch code reading JSON file Android

having some serious problem when trying to read a local JSON file. I've looked everywhere for many days now and the best and farthest I could get was copying from Faizan's answer.
Reading a json file in Android
How come that Android Studio doesn't let me generate the second try-catch code block here?
Help and advice are very much appreciated!!
This is My code
public String loadJSONFromAsset() {
String json = null;
try {
InputStream is = getAssets().open("names.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}
String jsonString = loadJSONFromAsset();
try {
JSONObject json = new JSONObject(jsonString);
JSONObject jObject = json.getJSONObject("female");
JSONObject jObject2 = jObject.getJSONObject("adult");
String name = jObject2.toString();
}
catch (Exception e) {
e.printStackTrace();
}
}
How come that Android Studio doesn't let me generate the second
try-catch code block here?
Simply, because your code is not inside a method.
Doing something like below should solve the error.
public void someMethodIdentifier(){ // doesn't have to be void return type, you know better than me what type you want to return.
String jsonString = loadJSONFromAsset();
try {
JSONObject json = new JSONObject(jsonString);
JSONObject jObject = json.getJSONObject("female");
JSONObject jObject2 = jObject.getJSONObject("adult");
String name = jObject2.toString();
}
catch (Exception e) {
e.printStackTrace();
}
}
Note - from the looks of the statements that's contained within the try block I think you intended to return some data? if that's the case just replace the void return type with the appropriate return type and return that data.

Batch process large file split by line endings using FTP streaming in Mule

I'm trying to read in a large file, 100K+ rows, split the file and process the rows. I've set the FTP connector to stream as the file is too large to read into memory but the payload is InputStream which cannot be read into the batch process.
I have a custom java component which converts the InputStream to a String but I want to be able to return the value in batches (as building the string will ultimately lead to Out of Memory errors anyway) but if I set a counter then the the java component stops reading the InputStream.
After this I use a splitter to turn the payload into a Iterable object so the batch process can execute.
Is there a way to return the value from the custom java component and continue processing the file to return batches of 500? Or is there a way to make the batch process read InputStream datatypes?
I can't find anything online
<flow name="bulk-flow">
<ftp:inbound-endpoint host="${ftp.host}" port="${ftp.port}" path="${ftp.path}" user="${ftp.user}" password="${ftp.pass}" connector-ref="ftpConnector" responseTimeout="10000" doc:name="FTP" pollingFrequency=1000"></ftp:inbound-endpoint>
<batch:execute name="batch" doc:name="batch"></batch:execute>
</flow>
<batch:job name="batch">
<batch:input>
<custom-transformer class="InputStreamToString" doc:name="Java"></custom-transformer>
<splitter expression="#[payload.split('\n')]" doc:name="Splitter"></splitter>
</batch:input>
<batch:process-records>
and the custom java class
public class InputStreamToString extends AbstractMessageTransformer{
#Override
public String transformMessage(final MuleMessage muleMessage, String arg1)
throws TransformerException {
String result = "";
try {
if (muleMessage.getPayload() != null && muleMessage.getPayload() instanceof InputStream) {
InputStream is = (InputStream) muleMessage.getPayload();
result = getStringFromInputStream(is);
}
} catch (Exception e) {
throw new TransformerException(new EscapeUnicodeTransformer(), e);
}
return result;
}
// convert InputStream to String
private static String getStringFromInputStream(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
int count = 0;
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null && count < 500) {
sb.append(line);
sb.append("\n");
count++;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
Thanks a lot for any ideas!

Automated Telnet client using commons-net

My requirement is to connect to some server through telnet using a java program and run few commands and read the responses. Based on these responses I need to perform some operation
I strated with https://stackoverflow.com/a/1213188/1025328
I'm using commons-net and my program is something like this:
public class TelnetSample {
private TelnetClient telnet;
private InputStream in;
private PrintStream out;
public TelnetSample(String server, int port) {
try {
// Connect to the specified server
telnet = new TelnetClient();
telnet.connect(server, port);
in = telnet.getInputStream();
out = new PrintStream(telnet.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
public String readResponse() {
System.out.println("TelnetSample.readResponse()");
StringBuilder out = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(out.toString());
System.out.println("==========================================================");
return out.toString();
}
public String read2() {
System.out.println("TelnetSample.read()");
StringBuffer sb = new StringBuffer();
try {
int available = in.available();
for (int index = 0; index < available; index++) {
char ch = (char) in.read();
System.out.print(ch);
sb.append(ch);
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
public String sendCommand(String command) {
try {
InputStream is = new ByteArrayInputStream(command.getBytes());
int ch;
while ((ch = is.read()) != -1) {
out.write(ch);
out.flush();
}
System.out.println(command);
String output = read2();
if (output.trim().isEmpty()) {
System.out.println("output empty");
} else {
System.out.println(output);
}
System.out.println("==========================================================");
return output;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void disconnect() {
try {
telnet.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
TelnetSample telnet = new TelnetSample("aspmx2.xxxxxx.com", 25);
telnet.readResponse();
telnet.sendCommand("Helo hi");
telnet.sendCommand("mail from:xyz#testmail.com");
telnet.sendCommand("rcpt to:pk#testmail.com");
telnet.sendCommand("quit");
telnet.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here apart form the telnet connection response, for every other sendCommand I'm getting an empty response. Can some one point me what could be the issue.
My output is something like this
TelnetSample.readResponse()
220 mx.xxxxxx.com ESMTP o86si4086625pfi.217 - gsmtp
==========================================================
Helo hi
TelnetSample.read()
output empty
==========================================================
mail from:xyz#testmail.com
TelnetSample.read()
output empty
==========================================================
rcpt to:pk#testmail.com
TelnetSample.read()
output empty
==========================================================
quit
TelnetSample.read()
output empty
==========================================================
This code has several issue:
the first issue is in readResponse method. When you use
readLine() you can easy block your code and will wait forever. Please have a look at discussion How to determine the exact state of a BufferedReader?
the second you don't send any CR/LF chars. Server got your requests like a single line. Ex:
mail from:xyz#testmail.comrcpt to:pk#testmail.comquit
To fix first issue you can choose several ways:
use multi-threading model
use NIO API. I would recommend Netty for that. Especially for your case as i can see you didn't use Telnet protocol at all, you connected to SMTP server.
Quick fix but the worst, wait first line from server and go on:
public String readResponse() {
System.out.println("TelnetSmtpSample.readResponse()");
StringBuilder out = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
out.append(reader.readLine());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(out.toString());
System.out.println("=====================");
return out.toString();
}
To fix second one:
telnet.sendCommand("Helo hi\r\n");
telnet.sendCommand("mail from:xyz#testmail.com\r\n");
telnet.sendCommand("rcpt to:pk#testmail.com\r\n");
telnet.sendCommand("quit\r\n");
It's possible read2 is getting a null value back from the input stream before data is actually returned. Try something like this:
private String read2() {
StringBuffer sb = new StringBuffer();
try {
do {
if (in.available() > 0) {
char ch = (char) in.read();
sb.append(ch);
} else {
Thread.sleep(1000);
}
} while (in.available()>0);
String output = new String(sb);
return output;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

Serialized object java

Today I started using serialized object in java, I'm new at it and I have some problems when I try to deserialize.
I have this file where I write all my Account objects, it writes fine I guess. The problem is I don't know how to refer to a specific object from that file, or how could I get all of them into a list? and then refer to it.
This is how i'm trying to read them:
public void readAccount(Account e) {
/* List<Account> results = new ArrayList<Account>();
try {
FileInputStream fileIn = new FileInputStream("test.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
for (int i = 0; i < accBank.size(); i++) {
results.add((Account) in.readObject());
}
in.close();
fileIn.close();
} catch (IOException i) {
i.printStackTrace();
return;
} catch (ClassNotFoundException c) {
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
for (Account acc : results) {
System.out.println(toString(acc));
if(e.getAcc_no() == acc.getAcc_no())
{System.out.println("Deserialized Account...");
System.out.println(toString(e));
}
}
*/
List<Account> results = new ArrayList<Account>();
Account acc = null;
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
while (true) {
ObjectInputStream ois = new ObjectInputStream(fis);
results.add((Account) ois.readObject());
acc = (Account) ois.readObject();
}
} catch (Exception ignored) {
// as expected
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
System.out.println("results = " + results);
for (Account ac : results) {
System.out.println(toString(ac));
if(e.getAcc_no() == ac.getAcc_no())
{System.out.println("Deserialized Account...");
System.out.println(toString(e));
}
}
}
And this is how I write them:
public void writeAccount(Account e) {
try {
ObjectOutputStream os1 = new ObjectOutputStream(
new FileOutputStream("test.txt", true));
os1.writeObject(e);
os1.close();
} catch (Exception exc) {
exc.printStackTrace();
}
}
Edit:
public void writeFile() {
for (int i = 0; i < accBank.size(); i++) {
writeAccount(retAcc(i));
}
}
Can any of you tell me what im doing wrong? I also tried other examples from other questions and didn't work.
What you're doing wrong is that you use several ObjectOutputStreams to write to the same file (which is not a txt file, BTW, since it contains binary data), and use a single ObjectInputStream to read all the accounts. As a consequence, a new serialization header is written each time you write an account, and the ObjectInputStream doesn't expect that.
The best way to write a list of accounts is to do just that: you store the accounts into a List<Account>, and write the list. To read the list of accounts, you do just that: you read a single object from the file, and cast it to List<Account>.

Categories