I have a Spring REST service set up which has a POST method to receive a byte array. The goal of this method is to accept a zipped JSON string, hence the byte array. The unzipped string is to be mapped to a list and then sent to a database.
#RequestMapping(value = "/receiveData.do", method = RequestMethod.POST)
public
#ResponseBody boolean receiveData(#RequestParam byte[] data,
#RequestParam String configurationName) {
String jsonString = ZipController.unZip(data);
JSONMapper jsonMapper = new JSONMapper();
List<Message> messages = null;
try {
messages = jsonMapper.parseToMessage(jsonString, configurationName);
saveData(messages);
} catch (Exception e) {
return false;
}
return true;
}
The zipping and the unzipping of the String works without flaws, as tests that I have written show. The converting to a list and then storing it in a database works perfectly too. However, when I zip a string, and send it to the address, somehow it isn't recognized as a zip anymore. Further digging revealed that the actual byte[] has completely changed in the process. Before I send it, the array prints to
[B#7186333e
However, after sending it, it suddenly prints to (for example)
[B#fee07cc
This appears to be random, but the [B# is always the same. The rest is random. I am using the REST-assured framework to test, but SOAPui gives the same problem. The code I'm using to send the call is:
expect().
body(containsString("true")).
when().
given().
parameters("data",ZipController.zip(correctJSONMessage)).
post("/receiveData.do");
The method returns a true or false as feedback whether it succeded or not.
The whole service runs on a Tomcat 6 server, is it possible that this messes with the array? How can I fix this?
Related
I've been recently working with Hyperledger Fabric using kotlin as a development language. I have the local test network fully working and after some time i have pretty good understanding on how everything works. However, im still stuck passing arguments to the chaincode as Strings because every time i try to pass objects as ByteArrays it implodes somehow along the way before it reaches my chaincode method. Here is a sample of the client sending the data and the chaincode entrypoint:
Client
val tl = MyClass()
tl.machineKey = "machineHashKey"
val path = File("/var/cenas.txt")
tl.loadFileFromPath(path.toPath())
try {
contract!!.submitTransaction(
"testLimitSet", tl.toByteArray()
)
}catch (e: Exception){
printException(e)
}finally {
println("*** Transaction completed")
}
ChainCode:
#Transaction(intent = Transaction.TYPE.SUBMIT)
fun testLimitSet(ctx: Context, testLimit: ByteArray){
println("Here 1!")
val id = IdentityChecks.checkIdentity(ctx)
println("Here 2!")
val x509 = id.second
println("Here 3!")
}
MyClass simply contains 2 text fields and 1 byteArray.
I've already managed to serialize it and deserialize it locally.
The log on the chaincode machine is the following:
Thread[fabric-txinvoke:3,5,main] 16:39:28:613 INFO org.hyperledger.fabric.contract.ContractRouter processRequest Got routing:testLimitSet:pt.fraunhofer.newgen.chaincode.NewGenMainContract
Thread[fabric-txinvoke:3,5,main] 16:39:28:625 SEVERE org.hyperledger.fabric.Logger error A JSONArray text must start with '[' at 1 [character 2 line 1]org.json.JSONException: A JSONArray text must start with '[' at 1 [character 2 line 1]
at org.json.JSONTokener.syntaxError(JSONTokener.java:507)
at org.json.JSONArray.<init>(JSONArray.java:109)
at org.json.JSONArray.<init>(JSONArray.java:162)
at org.hyperledger.fabric.contract.execution.JSONTransactionSerializer.convert(JSONTransactionSerializer.java:267)
at org.hyperledger.fabric.contract.execution.JSONTransactionSerializer.fromBuffer(JSONTransactionSerializer.java:165)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.convertArgs(ContractExecutionService.java:99)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.executeRequest(ContractExecutionService.java:57)
at org.hyperledger.fabric.contract.ContractRouter.processRequest(ContractRouter.java:123)
at org.hyperledger.fabric.contract.ContractRouter.invoke(ContractRouter.java:134)
at org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask.call(ChaincodeInvocationTask.java:106)
at org.hyperledger.fabric.shim.impl.InvocationTaskManager.lambda$newTask$17(InvocationTaskManager.java:265)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
I think im most likely using the ByteArray arguments improperly. But i haven't found any chaincode examples in java/kotlin receiving data as ByteArrays.
Thanks in advance
When using the contract api in your chaincode implementation it uses JSON as the serialisation mechanism and thus expects information sent from the client to be in stringified JSON format.
The client sdks don't do this for you as for example you can write chaincode without the contract api and define your own serialiation mechanism.
With the line
contract!!.submitTransaction(
"testLimitSet", tl.toByteArray()
)
you are sending an array of bytes as the string which won't mean anything to a JSON Parser. You need to convert tl.toByteArray() into a stringified JSON representation of that data, for example a stringified JSON representation of an array with bytes 01,02,03 might look like
'["\u0001","\u0002","\u0003"]'
However I am not really familiar with the java chaincode libraries so whether this will actually work I don't know given that the JSON representation allows for values larger that bytes and that may cause the contract api to deserialize the JSON into something that isn't type compatible with what you declare on your chaincode ie testLimit: ByteArray you may need to change the type or perhaps send the binary data in a different manner, for example encode it as a base64 string then send a string instead
I've solved the problem by creating a string representation of the ByteArray. It is not the solution i originally wanted, but it works well nevertheless. I still find it strange to the SDK to provide this method:
byte[] submitTransaction(String name, byte[]... args)
and im not able to use it because it doesn't reach the chaincode endpoint with the problem described above.
My solution uses this instead:
byte[] submitTransaction(String name, String[]... args)
Here is my current solution:
val tl = MyClass()
tl.machineKey = "machineHashKey"
val path = File("/var/cenas.txt")
tl.loadFileFromPath(path.toPath())
try {
val payload = tl.toByteArrayString()
contract!!.submitTransaction(
"testLimitSet", payload
)
}catch (e: Exception){
printException(e)
}finally {
println("*** Transaction completed")
}
Where:
fun toByteArrayString(): String {
return toHexString(this.toByteArray())
}
// String <- Hex(ByteArray)
fun toHexString(ba: ByteArray): String {
return BaseEncoding.base16().encode(ba)
}
// String -> Hex(ByteArray)
fun toByteArray(s: String): ByteArray {
return BaseEncoding.base16().decode(s)
}
Note that this is using
import com.google.common.io.BaseEncoding
but there are multiple implementations that can be used for this
Can someone helps me to get json from the web.In the end of function jsonResponse is empty. I use this method to do it:
private String getJson() {
jsonResponsce = "";
AsyncTask.execute(new Runnable() {
#Override
public void run() {
try{
URL httpbinEndpoint = new URL(webPage);
HttpsURLConnection myConnection = (HttpsURLConnection) httpbinEndpoint.openConnection();
myConnection.setRequestMethod("GET");
// Enable writing
myConnection.setDoOutput(true);
String internetData = "";
// Write the data
myConnection.getOutputStream().write(internetData.getBytes());
jsonResponsce = internetData;
} catch (IOException e) {
e.printStackTrace();
}
}
});
return jsonResponsce;
}
I set an Internet permission to the manifest. I try go get Json from the next address: https://shori-dodjo-mobile-app.firebaseio.com/.json. Full code is placed here: https://github.com/GenkoKaradimov/Shori-Dodjo-Android-App/
You are executing the request asynchronously so the method starts the execution and then completes and therefore there is no result. The result will be there in a second but by that time the method getJson has already completed. You most probably need to put the code that uses the json at the end of the run method.
In addition your code for reading from the stream seems wrong. It should probably be something like
BufferedReader br = new BufferedReader(new InputStreamReader(myConnection.getInputStream()));
jsonResponsce = br.lines().collect(Collectors.joining("\n"));
(I haven't tested this)
There are multiple issues in your code:
First, AsyncTask means it's async(hronous), so you can't return the result right away. Instead, override AsyncTask's onPostExecute and do what you need to do with the data there. Here is the sample implementation.
Second, you're using getOutputStream, which is intended for writing to the connection, i.e. sending data to the server. In your case you need to getInputStream and read from it. Easiest way is to wrap it in a BufferedReader and read until it returns -1 (marking end of stream), and then convert to string.
There are a few quirks: You should handle, or at least recognize errors by checking HTTP status code, handle encodings (the convert-bytes-to-string part), and handle cases when response is compressed, e.g. using DEFLATE or gzip. I've implemented that in a pure Java way (reference code, warning: outdated docs), but I'd seriously recommend using one of the established libraries such as Retrofit or Volley.
Json objects usually get return as HashMaps.
So you might need something like, HashMap yourMap = new HashMap<~>();
then
yourMap.get("the objects name on the other side", the var its getting saved too.);
right now it looks like all you are trying to do is save the byte data, but this byte data needs to have a type. Hope this helps.
Here is a live example of what I am talking about:
http://185.112.249.77:9999/Api/search?search=ж
That URL displays no results.
http://188.226.217.48:8338/api/clan_search/ж
It does display results.
How come this is happening?
My code for reading the parameter is: String search = request.getParameter("search");
System.out.println(search); also outputs a
?
I looked around and it seems there might be something I need to do in the Tomcat8 Config but I can't find what or figure out what has to be done.
I'd appreciate any help with this.
This problem also occurs when I am printing out the results. The first one shows no results and the 2nd shows the results and in UTF-8.
What is the most likely issue causing this and what code/config files would you need to see?
EDIT
I am receiving a bytearray which I am converting to an inputstream via a bytearrayinputstream like this.
InputStream myis = new ByteArrayInputStream(decryptedPayload);
I have a class which handles the packet and it extends a class I made called PacketInputStream. This class has a readString function which goes like this:
public String readString() throws IOException {
int length = readVarInt();
byte[] data = new byte[length];
readFully(data);
return new String(data, UTF8);
}
The string doesn't display properly on the returned byte[]s and it also doesn't work when I send it through a GET parameter.
Thanks
Hello i'm trying create an application allowing me host any kind of file.
In order to do it i'm exececuting following magic:
#RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
#ResponseBody
public FileSystemResource
getFile(
#PathVariable("file_name") String fileName) {
System.out.println(fileName);
String filePath = "./files/";
return new FileSystemResource(new File(filePath+fileName));
}
But this approach brings three unwanted problems:
Some random data is beeing appended to the file
The file gets opened in the browser window instead of beeing
downloaded - i've tried to hack this using something like
produces = "application/octet-stream"
but it only resulted in 406 error.
The test.txt is beeing truncated into test, i found a walkaround in providing the app with test.txt/ as fileName but it looks a bit messy.
As stated on spring manual
As with #RequestBody, Spring converts the returned object to a
response body by using an HttpMessageConverter
I think your problem is spring doesn't come with a HttpMessageConverter than can process FileSystemResource.
A list of builtin HttpMessageConverter is available here. I suggest you try converting your response into byte array somehow, maybe it will pick ByteArrayHttpMessageConverter instead and help solve your issue
I used code like this to return image
#RequestMapping(value = "/image/{id}", method = RequestMethod.GET)
public String getImage(... HttpServletResponse response) {
response.setContentType(image/png);
(response.getOutputStream()).write(imageByteArray);
}
I think you have to define proper mime type and send your data to response.
I have kind of a stupid question, but since I can't figure it out I figured I'd post it here to see if anyone can help!
I have some code that makes an HttpPost request to our server. I receive the results perfectly in an XML format. The problem is I want to get the boolean value that is returned, not just a String. So for example, a successful call to the web service returns this xml:
<boolean xmlns="https://myWebService/">false</boolean>
which I can access and read by using this line:
String responseBody = EntityUtils.toString(response.getEntity());
Is there a way to access the data returned (false, in this case) as a boolean, or will I have to manually parse the return String to get the value?
Thanks for your help
will I have to manually parse the return String to get the value?
Yes, but you can simply roll your own method that does the parsing (and etc.) and then returns a boolean.
public boolean asBoolean(Entity e){
return Boolean.parseBoolean(EntityUtils.toString(e));
}