I have this file which contains python pickle data stream. I've to read contents of this file in Android.
For example, if I wanted to read this data stream in python, I'd just use the following code
queue = pickle.load(open('filename', 'rb'))
I want to achieve same thing in Android such that I can read this pickle stream data and store it in some kind of collection.
How can I achieve this?
UPDATE: This only works for pickle protocols 2 and 3.
I think the Unpickler class from Pyrolite (MIT license) may be of particular interest to you. It is technically Java, but Android is basically Java. To unpickle you would do something similar to the following:
InputStream stream = new FileInputStream("filename");
Unpickler unpickler = new Unpickler();
Object data = unpickler.load(stream);
// And cast *data* to the appropriate type.
With the imports:
import java.io.FileInputStream;
import java.io.InputStream;
import net.razorvine.pickle.Unpickler;
These are the objects supported by default:
PYTHON ----> JAVA
------ ----
None null
bool boolean
int int
long long or BigInteger (depending on size)
string String
unicode String
complex net.razorvine.pickle.objects.ComplexNumber
datetime.date java.util.Calendar
datetime.datetime java.util.Calendar
datetime.time java.util.Calendar
datetime.timedelta net.razorvine.pickle.objects.TimeDelta
float double (float isn't used)
array.array array of appropriate primitive type (char, int, short, long, float, double)
list java.util.List<Object>
tuple Object[]
set java.util.Set
dict java.util.Map
bytes byte[]
bytearray byte[]
decimal BigDecimal
custom class Map<String, Object> (dict with class attributes including its name in "__class__")
Please also note:
The unpickler simply returns an Object. Because Java is a statically typed
language you will have to cast that to the appropriate type. Refer to this
table to see what you can expect to receive.
UPDATE: I ran tests using the various pickle protocols (0-3) and found that it fails for 0 and 1, but succeeds for 2 and 3.
Here's the python code used to generate the pickled data:
import pickle
class Data(object):
def __init__(self):
self.x = 12
data = Data()
for p in [0, 1, 2]:
with open('data.{}'.format(p), 'wb') as fh:
pickle.dump(data, fh, protocol=p)
# Python 3 only.
with open('data.3', 'wb') as fh:
pickle.dump(data, fh, protocol=3)
And the java code to unpickle it:
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Map;
import net.razorvine.pickle.Unpickler;
public class Test {
public static void main(String[] args) throws IOException {
String filename = args[0];
InputStream inputStream = new FileInputStream(filename);
Unpickler unpickler = new Unpickler();
Map<String, Object> data = (Map<String, Object>)unpickler.load(inputStream);
}
}
When run with data.0 and data.1, it fails with:
Exception in thread "main" net.razorvine.pickle.PickleException: expected zero arguments for construction of ClassDict (for copy_reg._reconstructor)
at net.razorvine.pickle.objects.ClassDictConstructor.construct(ClassDictConstructor.java:23)
at net.razorvine.pickle.Unpickler.load_reduce(Unpickler.java:617)
at net.razorvine.pickle.Unpickler.dispatch(Unpickler.java:170)
at net.razorvine.pickle.Unpickler.load(Unpickler.java:84)
at Test.main(Test.java:13)
When run with data.2 and data.3, it succeeds.
Related
I am developing an android application in which i want to parser the date, time and string that is what Natty do is exactly needed for me. I have tried in eclipse IDE. I have manually added the following jar files.
antlr-2.7.7.jar
antlr-runtime-3.2.jar
backport-util-concurrent-3.1.jar
commons-codec-1.5.jar
commons-lang-2.6.jar
commons-logging-1.1.1.jar
ical4j-1.0.2.jar
stringtemplate-3.2.jar
And i have followed the instructions given in Natty website.
That is in POM file. i have added the dependency as
<dependency>
<groupId>com.joestelmach</groupId>
<artifactId>natty</artifactId>
<version>0.11</version>
</dependency>
and
added the following in main java file.
import com.joestelmach.natty.*;
Parser parser = new Parser();
List groups = parser.parse("the day before next thursday");
for(DateGroup group:groups) {
List dates = group.getDates();
int line = group.getLine();
int column = group.getPosition();
String matchingValue = group.getText();
String syntaxTree = group.getSyntaxTree().toStringTree();
Map parseMap = group.getParseLocations();
boolean isRecurreing = group.isRecurring();
Date recursUntil = group.getRecursUntil();
}
I have imported three libraries.
import java.util.Date;
import java.util.List;
import java.util.Map;
Now i am getting an error in this line.
for(DateGroup group:groups)
Error:
Type mismatch: cannot convert from element type Object to DateGroup.
Please suggest me some solutions for this.
I am trying to fix an issue with my RestTemplate PUT request. Basically, the server expects data(an object) to be put in "Raw" content-type but as xml stream.
I tried many combinations(of converter, content-type etc..) but nothing helps. I either end up in getting exception as " org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type com.test.myObject"
Or:
"The server encountered an error processing the request.
The exception message is 'Incoming message for operation 'SendRequest' contains
an unrecognized http body format value 'Xml'. The expected body format value is 'Raw'.
This can be because a WebContentTypeMapper has not been configured on the binding.
".
Any suggestions to fix this will be of great value.
You could provide your own message converter:
Considering that you need to send a custom Content-Type, you will need to create a class that extends AbstractHttpMessageConverter let's say RawHttpMessageConverter. You will need to provide concrete implementations for abstract methods:
supports(...) - feel free to return true
readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage) - here you'll unmarshall your custom object from inputMessage.getBody() InputStream
writeInternal(T t, HttpOutputMessage outputMessage) - here you'll marshall your object T into outputMessage.getBody() OutputStream
Also, very important is to set the list of expected content types: new MediaType("Raw", "8"); and to register into your message converters list.
This is one way of doing it. Another way could be to extend an existing message converter and provide concrete implementations for only what you need. The closest message converter that I can see to your needs (If I understand them correctly) is StringHttpMessageConverter. When providing an implementation you will just create a List of MediaTypes as class variable and add "Raw" type to it - that in constructor. Override getSupportedMediaTypes() and return this list.
When setting up the RestTemplate you will have:
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<AbstractHttpMessageConverter<?>>> converters = new ArrayList<HttpMessageConverter<AbstractHttpMessageConverter<?>>>();
converters.add(new RawHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
To provide more, below is a custom message converter that I am using for Bitmap download:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
public class BitmapMessageConverter implements HttpMessageConverter<Bitmap> {
private static final int BUFFER_SIZE = 8 * 1024;
private List<MediaType> imageMediaTypes;
public BitmapMessageConverter() {
imageMediaTypes = new ArrayList<MediaType>();
imageMediaTypes.add(new MediaType("image", "*"));
imageMediaTypes.add(new MediaType("image", "png"));
imageMediaTypes.add(new MediaType("image", "jpeg"));
}
private boolean isRegisteredMediaType(MediaType mediaType) {
return imageMediaTypes.contains(mediaType);
}
#Override
public List<MediaType> getSupportedMediaTypes() {
return imageMediaTypes;
}
#Override
public Bitmap read(Class<? extends Bitmap> classArg, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
BufferedInputStream bis = new BufferedInputStream(inputMessage.getBody(), BUFFER_SIZE);
Bitmap result = BitmapFactory.decodeStream(bis);
return result;
}
#Override
public void write(Bitmap bitmap, MediaType mediaType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
BufferedOutputStream bos = new BufferedOutputStream(outputMessage.getBody(), BUFFER_SIZE);
bitmap.compress(CompressFormat.JPEG, 100, bos);
}
I'm trying to implement a custom gson serializer/deserialiser for some list of BasicNameValuePair objects.
I saw the partial solution code (for serialization) here:
How do I get Gson to serialize a list of basic name value pairs?
However I wanted to implement also deserialization and I tried my chances and the code is here:
package dto;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
public class KeyValuePairSerializer extends TypeAdapter<List<BasicNameValuePair>> {
#Override
public void write(JsonWriter out, List<BasicNameValuePair> data) throws IOException {
out.beginObject();
for(int i=0; i<data.size();i++){
out.name(data.get(i).getName());
out.value(data.get(i).getValue());
}
out.endObject();
}
#Override
public List<BasicNameValuePair> read(JsonReader in) throws IOException {
ArrayList<BasicNameValuePair> list=new ArrayList<BasicNameValuePair>();
in.beginObject();
while (in.hasNext()) {
String key = in.nextName();
String value = in.nextString();
list.add(new BasicNameValuePair(key,value));
}
in.endObject();
return list;
}
}
Code to initialize and fill the list
ArrayList<BasicNameValuePair> postParameters=new ArrayList<BasicNameValuePair>();
postParameters.add(new BasicNameValuePair("some_key","some_value"));
And here is the code to use the new KeyValuePairSerializer class:
GsonBuilder gsonBuilder= new GsonBuilder();
gsonBuilder.registerTypeAdapter(KeyValuePairSerializer.class, new KeyValuePairSerializer());
Gson gson1=gsonBuilder.create();
//serialization works just fine in the next line
String jsonUpdate=gson1.toJson(postParameters, KeyValuePairSerializer.class);
ArrayList<BasicNameValuePair> postParameters2 = new ArrayList<BasicNameValuePair>();
//postParameters2 = gson1.fromJson(jsonUpdate, KeyValuePairSerializer.class); //? how to cast properly
//deserialization throws an error, it can't cast from ArrayList<BasicNameValuePair> to KeyValuePairSerializer
gson1.fromJson(jsonUpdate, KeyValuePairSerializer.class);
The problem is that it throws an exception at the end and I don't know where exactly is the problem and still not sure how to write the last line to get the result back in the new postParameters2 ArrayList.
Adapted from the GSON Collections Examples:
GsonBuilder gsonBuilder= new GsonBuilder();
gsonBuilder.registerTypeAdapter(KeyValuePairSerializer.class, new KeyValuePairSerializer());
Gson gson1=gsonBuilder.create();
Type collectionType = new TypeToken<ArrayList<BasicNameValuePair>>(){}.getType();
ArrayList<BasicNameValuePair> postParameters2 = gson1.fromJson(jsonUpdate, collectionType);
registerTypeAdapter seems to work only for the serializer not for deserializer.
The only way to call the overridden read function of the KeyValuePairSerializer is to call the:
gson1.fromJson(jsonUpdate, KeyValuePairSerializer.class); without saving the result value in a variable. While it will process the function just fine, it will throw an error inside gson class because it will not be able to cast from the ArrayList to the KeyValuePairSerializer. And I kinda understand why (erasure I guess), just don't know how to do it properly.
Anyway I found a workaround to solve this issue.
It seems that instead of registering the gson object and calling registerTypeAdapter and then using gson1.toJson(Object src, Type typeOfSrc) and gson1.fromJson(String json,Class <T> classOfT) I can get away for deserialization with something simpler like:
KeyValuePairSerializer k= new KeyValuePairSerializer();
parametersList = (ArrayList<BasicNameValuePair>)k.fromJson(jsonUpdate);
Both JsonObject's and NameValuePair's behave in a similar way to dictionaries, I don't think you need to convert one into the other if the use case is similar. Additionally JsonObject allows you to treat your values even easier (instead of looping through the array of value pairs to find the key you need to get its value, JsonObject behaves similarly to a Map in a way that you can directly call the name of the key and it'll return the desired property):
jsonObject.get("your key").getAsString(); (getAsBoolean(), getAsInt(), etc).
For your case I'd create a JsonObject from your string, response or stream and then access it as a map (as shown above):
JsonParser parser = new JsonParser();
JsonObject o = (JsonObject)parser.parse("your json string");
I followed this blog for GSON Collection Examples .
Link is simple to understand and implement.
public class TimeSerializer implements JsonSerializer<time> {
/**
* Implementing the interface JsonSerializer.
* Notice that the the interface has a generic
* type associated with it.
* Because of this we do not have ugly casts in our code.
* {#inheritDoc}
*/
public JsonElement serialize(
final Time time,
final Type type,
final JsonSerializationContext jsonSerializationContext) {
/**
* Returning the reference of JsonPremitive
* which is nothing but a JSONString.
* with value in the format "HH:MM"
*/
return new JsonPrimitive(String.format("%1$02d:%2$02d",
time.getHour(), time.getMinute()));
}
I have successfully created a cloud endpoint model that allows for easy retrieval of information from App Engine. To reduce the roundtrips and provide a faster user experience, I have identified one instance I wish to store to local storage.
Throughout the rest of my app, I am using ObjectInputStream to read and write the objects such as:
FileInputStream fis = context.openFileInput("PRIVFILE");
ObjectInputStream ois = new ObjectInputStream(fis);
AppModelState s = (AppModelState) ois.readObject();
This obviously requires all data members to implement the Serializable interface. The Model class extends GenericJSON and is not "Serializable", as
public final class ModelClass extends GenericJson {}
I could manually create a serializable object that maps to the model; however, that seems very amateur due to the number of attributes.
The other alternative I considered was creating a Serializable Object wrapper that simply has the JSON string as a member and provides a setter/getter accepting the ModelClass as parameters, such as:
class AppModelState implements Serializable {
private String modelClassJSON;
public ModelClass getModelClass() {
// generate a new ModelClass from the JSON
}
public void setModelClass(ModelClass c) {
// extract the JSON for storage
}
.....
}
I feel like there must be a better way and this should have been solved a dozen times but I am not finding any resources. Please provide input.
I'm doing exactly the same as you say in your question.
Since Cloud Endpoints objects are already serialized for transmit over the wire, they are also serializable to be stored locally. As an added bonus, with Android 3.0 or later, you don't even need to import any libraries -- it's already there! For example:
import com.google.api.client.extensions.android.json.AndroidJsonFactory;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
private static final JsonFactory JSON_FACTORY = new AndroidJsonFactory();
public void putObject(String key, Object value) throws Exception {
byte[] outputbytes = null;
if (value instanceof GenericJson) {
outputbytes = JSON_FACTORY.toByteArray(value);
} else {
ByteArrayOutputStream output = new ByteArrayOutputStream();
ObjectOutputStream objectstream = new ObjectOutputStream(output);
objectstream.writeObject(value);
objectstream.close();
outputbytes = output.toByteArray();
}
// persist "outputbytes" ...
}
public <T> T getObject(String key, Class<T> outclass) throws Exception {
// retrieve saved bytes...
byte[] valuebytes = ...
if (valuebytes[0] == '{' && valuebytes[1] == '"' && valuebytes[valuebytes.length-1] == '}') {
// Looks like JSON...
return JSON_FACTORY.fromString(new String(valuebytes, "UTF-8"), outclass);
} else {
ByteArrayInputStream input = new ByteArrayInputStream(valuebytes);
ObjectInputStream objectstream = new ObjectInputStream(input);
Object value = objectstream.readObject();
objectstream.close();
return outclass.cast(value);
}
}
Note that the default AndroidJsonFactory (as of Android v4.3, anyway) is quite slow when serializing long strings. Create a new JacksonFactory instead if you have performance problems. Everything else stays the same.
Update: If you want to serialize a list of GenericJson objects, you just have to create a GenericJson object that includes a list of those objects. For example:
import com.google.api.client.json.GenericJson;
import com.google.api.client.util.Key;
public static class PersistantJson extends GenericJson {
#Key public int one;
#Key public String two;
}
public static class PersistantJsonList extends GenericJson {
#Key public List<PersistantJson> list = new ArrayList<PersistantJson>();
}
You can now add all your PersistantJson (i.e. some class created by "generate cloud endpoint client library") objects to the .list element of a PersistantJsonList variable and then pass that variable to putObject(). Note that this requires all objects in the list to be of the same class so that deserialization knows what the type is (because JSON serialization does not record the type). If you use List<Object> then what is read back is a List<Map<String, Object>> and you have to extract the fields manually.
I think that doing standard Java serialization of classes that will be used with Endpoints doesn't work very well. The problem is that serialization is binary, and HTTP comm is string.
If you were doing the HTTP comm yourself, rather then using endpoints, I think you would have the same problem. In order to send the object you would serialize it (converting an string members to binary) and then you would have to convert the binary back to string.
So, if the amount of data you are using is not too much, it would probably be easiest to store your objects as JSON.
I have a java class where it reads some data from a text file using a buffered reader and returns that data as a hash map:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
public class FrequencyLoader {
public FrequencyLoader() throws FileNotFoundException {
}
public HashMap<String, Double> loadUnigramFrequencies() throws FileNotFoundException, IOException {
HashMap<String, Double> unigramFrequencies = new HashMap<String, Double>();
String line;
String[] splittedLine;
BufferedReader bf = new BufferedReader(new FileReader("unigramFrequencies.txt"));
while ((line = bf.readLine()) != null) {
splittedLine = line.split("\\s");
unigramFrequencies.put(splittedLine[0].trim(), Double.parseDouble(splittedLine[1].trim()));
}
return unigramFrequencies;
}
}
I want to use that in my android application but when I create an instance of this class and try to execute the loadUnigramFrequencies() function in the android Activity class I am getting an error that the application has stopped unexpectedly. I am trying to run it on Samsung Galaxy S2. Should the file be placed somewhere in the android project rather than on the disk? if yes then where?
without a bit of logcat it is a bit trivial.
unigramFrequencies.put(splittedLine[0].trim(), Double.parseDouble(splittedLine[1].trim()))
here for instance could be raised a null pointer execption if splittedLine[0] or splittedLine[1] is null, or parseDouble could arise a number format execption
I think the error might well be there :
BufferedReader bf = new BufferedReader(new FileReader("unigramFrequencies.txt"));
You should provide an absolute path here and first make sure that the file exists before accessing it or handle the exception.
If this file is some final asset, you should place it in your project assets folder and get a filereader from there.
Example (from here):
AssetFileDescriptor descriptor = getAssets().openFd("unigramFrequencies.txt");
FileReader reader = new FileReader(descriptor.getFileDescriptor());
Note that your unigramFrequencies.txt file should be present in your <project>/assets/ directory
This is searching for a needle in the hay stack.
I recommend you to first learn how to use debugging in Android:
http://www.droidnova.com/debugging-in-android-using-eclipse,541.html
Also some exception handling wouldn't hurt:
http://en.wikibooks.org/wiki/Java_Programming/Throwing_and_Catching_Exceptions
The following line of code is very wrong, and it seems you don't understand file storage in android:
new FileReader("unigramFrequencies.txt")
Here it is explained:
http://developer.android.com/guide/topics/data/data-storage.html