I would like to write serializer for Ehcache of Optional class. I know, that optional member is seriazizable, so I write:
#Override
public ByteBuffer serialize(Optional object) throws SerializerException {
if( object.isPresent() ) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
return ByteBuffer.wrap(baos.toByteArray()); // excess copying
} catch (IOException e) {
throw new AssertionError(e);
}
}
else {
return ByteBuffer.wrap(new byte[] {});
}
}
#Override
public Optional read(ByteBuffer binary) throws ClassNotFoundException, SerializerException {
if( binary.array().length > 0 ) {
try {
byte[] buf = binary.array();
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(bais);
Object object = ois.readObject();
return Optional.of(object);
} catch (IOException e) {
throw new AssertionError(e);
}
}
else {
return Optional.empty();
}
}
I confused by commented line, which includes excess copying of data. Can I avoid it and serialize directly with ByteBuffer?
While does Ehcache seriazliers based of ByteBuffer?
ByteBuffer.wrap() doesn't actually copy data. As the name implies it wraps the array, so any changes to the original array would also be reflected in the buffer.
Sadly, you can't do Java serialization on a ByteBuffer. You are doing the same thing as the built-in PlainJavaSerializer of Ehcache.
By the way, you could remove a lot of code by doing this:
public class OptionalSerializer<T> implements Serializer<Optional<T>> {
private final PlainJavaSerializer<T> serializer;
public OptionalSerializer(ClassLoader classLoader) {
serializer = new PlainJavaSerializer<>(classLoader);
}
#Override
public ByteBuffer serialize(Optional<T> object) throws SerializerException {
return object.map(serializer::serialize).orElse(ByteBuffer.allocate(0));
}
#Override
public Optional<T> read (ByteBuffer binary) throws ClassNotFoundException, SerializerException {
if(binary.array().length > 0) {
return Optional.of(serializer.read(binary));
}
return Optional.empty();
}
#Override
public boolean equals(Optional<T> object, ByteBuffer binary) throws ClassNotFoundException, SerializerException {
return object.equals(read(binary));
}
}
Related
Since Entity store is throwing out when storing null value, I managed to get a "hack" to save a null value into it. However I am not sure if my approach is futile.
Here's a snippet:
entityStore.executeInTransaction(new StoreTransactionalExecutable() {
#Override
public void execute(#NotNull final StoreTransaction txn) {
try {
entityStore.registerCustomPropertyType(txn, UndefinedIterable.class, UndefinedBinding.BINDING);
} catch (Exception e) {
}
final Entity entity = txn.newEntity(storeName);
Iterator<String> it = comparableMap.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
Comparable value = comparableMap.get(key);
if(value == null) {
entity.setProperty(key, new UndefinedIterable());
} else {
entity.setProperty(key, value);
}
}
First question here is, is it safe to registerCustomPropertyType over and over again, since this method will be called each time the server gets a POST request.
Next is the UndefinedIterable even needed here?
Here's the complete code
UndefinedIterable.java
public class UndefinedIterable implements Serializable, ByteIterable {
private byte[] bytes;
public UndefinedIterable() {
bytes = "null".getBytes();
}
#Override
public ByteIterator iterator() {
return new ArrayByteIterable(bytes).iterator();
}
#Override
public byte[] getBytesUnsafe() {
return bytes;
}
#Override
public int getLength() {
return bytes.length;
}
#NotNull
#Override
public ByteIterable subIterable(int offset, int length) {
return null;
}
#Override
public int compareTo(#NotNull ByteIterable o) {
return 0;
}
}
UndefinedBinding.java
public class UndefinedBinding extends ComparableBinding {
public static final UndefinedBinding BINDING = new UndefinedBinding();
#Override
public Comparable readObject(#NotNull ByteArrayInputStream stream) {
try {
byte[] serialized = ByteStreams.toByteArray(stream);
Comparable deserialized = deserialize(serialized, Comparable.class);
return deserialized;
} catch (Exception e) {
}
return null;
}
#Override
public void writeObject(#NotNull LightOutputStream output, #NotNull Comparable object) {
byte[] serialized = serialize(object);
output.write(serialized);
}
public static byte[] serialize(Object obj) {
try {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos)) {
out.writeObject(obj);
return bos.toByteArray();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static <T> T deserialize(byte[] data, Class<T> clazz) {
try {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
return (T) is.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
I am afraid that my approach might be a bit overkill for the simple job of saving a null value?
It's safe to registerCustomPropertyType several times, though it is intended to be called usually once on an init stage.
If I really need to distinguish lack of property value and property having null value, then I'd try to define non-null values replacing null. For String, it can be hex representation of an UUID. For Integer, Integer.MIN_VALUE or Integer.MAX_VALUE, etc. Don't use values of mixed types for a single property, otherwise search by property value or range search won't work.
I am coding in java and I have a problem
I am using an interface (that the teacher gave us and we cant change it), the interface obligate you to implement a function with a byte array is input and through this array you can transfer any data you want.
I need to pass a few different objects with unknown size ,is there a way to do it? I can obviously put the size of every object at the beginning but this is very difficult is there any easier way to do it?
I also need to pass data in a byte array from another language like c or cpp
so the technique must be non specific to java
here is a simple example of what the code looks like
void myFunc(byte[] arr)
{
byte[] name; // arr[0:10] string in ascii
byte[] lastName; //arr[10:k] string in ascii
byte[] currentUnixTime; //arr[k:arr.lenfth] this is an int
some operations.....
}
So without further details you can generically send Object through serialization but it might not always be a good idea. Here is a fairly generic implementation of Object serialization.
interface Sender {
void write(OutputStream outputStream, Object... objects);
List<Object> read(InputStream inputStream);
}
class Homework implements Sender {
#Override
public void write(OutputStream stream, Object... objects) {
for (Object obj : objects) {
try (ObjectOutputStream objStream = new ObjectOutputStream(stream)) {
objStream.writeObject(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public List<Object> read(InputStream stream) {
List<Object> objectList = new ArrayList<>();
try (ObjectInputStream objStream = new ObjectInputStream(stream)) {
Object obj;
while ((obj = objStream.readObject()) != null) {
objectList.add(obj);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return objectList;
}
}
Edit: I misunderstood the question. Here is a implementation that uses byte[]s
interface Sender {
byte[] write(Object... objects);
List<Object> read(byte[] bytes);
}
class Homework implements Sender {
#Override
public byte[] write(Object... objects) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (ObjectOutputStream objStream = new ObjectOutputStream(out)) {
for (Object obj : objects) {
objStream.writeObject(obj);
}
objStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
return out.toByteArray();
}
#Override
public List<Object> read(byte[] bytes) {
List<Object> objectList = new ArrayList<>();
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(bytes);
try (ObjectInputStream objStream = new ObjectInputStream(byteInputStream)) {
Object obj;
while ((obj = objStream.readObject()) != null) {
objectList.add(obj);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return objectList;
}
}
Then to use it.
Homework homework = new Homework();
String helloWorld = "hello world";
byte[] helloBytes = homework.write(helloWorld);
assert homework.read(helloBytes).get(0).equals(helloWorld);
In the end what I did was this -
I converted to base 32 every object that I wanted to send ,then in between each converted object I added a ',' to separate the object (since ',' isn't needed for base 32 representation).
after that the analysis was simple
I have a view object that needs to be serialized to store in a database, and then retrieved later
public class MachineView extends View implements Serializable {
String name;
int age;
public MachineView(String name, int age, Context context) {
super(context);
this.name = name;
this.age = age;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
int radius;
radius = 50;
Paint paint = new Paint();
//paint.setStyle(Paint.Style.FILL);
paint.setTextSize(x / 2);
...
}
}
The only problem is that the methods I am using to serialize objects only work for simple objects( i.e. objects that can be condensed to key value pairs )
below are serialize and read object methods:
//Serialize object
public static byte[] getSerializedObject(Serializable s) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(s);
} catch (IOException e) {
return null;
} finally {
try {
oos.close();
} catch (IOException e) {}
}
byte[] result = baos.toByteArray();
return result;
}
//read object
public static Object readSerializedObject(byte[] in) {
Object result = null;
ByteArrayInputStream bais = new ByteArrayInputStream(in);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bais);
result = ois.readObject();
} catch (Exception e) {
result = null;
} finally {
try {
ois.close();
} catch (Throwable e) {
}
}
return result;
}
It seems that i can convert the object into a byte array, but every time i read the object back it returns null
your code works fine for me:
import java.io.*;
class Foo implements Serializable {
#Override public String toString() {
return "Foo [x="+x+"]";
}
int x;
}
class Bar implements Serializable {
#Override public String toString() {
return "Bar [foo="+foo+"]";
}
Foo foo;
}
public class Soxx {
public static byte[] getSerializedObject(Serializable s) {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=null;
try {
oos=new ObjectOutputStream(baos);
oos.writeObject(s);
} catch(IOException e) {
return null;
} finally {
try {
oos.close();
} catch(IOException e) {}
}
byte[] result=baos.toByteArray();
return result;
}
//read object
public static Object readSerializedObject(byte[] in) {
Object result=null;
ByteArrayInputStream bais=new ByteArrayInputStream(in);
ObjectInputStream ois=null;
try {
ois=new ObjectInputStream(bais);
result=ois.readObject();
} catch(Exception e) {
result=null;
} finally {
try {
ois.close();
} catch(Throwable e) {}
}
return result;
}
public static void main(String[] args) {
Foo foo=new Foo();
foo.x=42;
Bar bar=new Bar();
bar.foo=foo;
byte[] bytes=getSerializedObject(bar);
Object object=readSerializedObject(bytes);
System.out.println(object);
}
}
outputs: Bar [foo=Foo [x=42]]
I have a HashMap where i store last read time of multiple sources which i needs to be backed up to a file. The same hashmap is updated regularly and should be backed up every time.
I am using ObjectOutputStream for this, as the same object is updated i was doing a reset() on the ObjectOutputStream, so that the file is updated, but with this is see and for every writeObject() a new line is written to the file this should be because the object is appended to the file. My service is long running service, so i can't afford the object to be appended every time as that will cause the file to become huge.
Here is a snippet of my code
public void open() throws WCException {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(bookmarkFile));
bookmarks = (HashMap<String, Long>) objectInputStream.readObject();
objectInputStream.close();
} catch (ClassNotFoundException | IOException e) {
}
try {
fileOutputStream = new FileOutputStream(bookmarkFile);
objectOutputStream = new ObjectOutputStream(fileOutputStream);
} catch (IOException e) {
throw new WCException("Bookmarker", e.getCause());
}
}
public void close() throws WCException {
try {
objectOutputStream.close();
fileOutputStream.close();
} catch (IOException e) {
throw new WCException("Bookmarker", e.getCause());
}
}
public synchronized void write() throws WCException {
try {
objectOutputStream.writeObject(bookmarks);
objectOutputStream.reset();
} catch (IOException e) {
throw new WCException("Bookmarker", e.getCause());
}
}
public synchronized void update(HashMap<String, Long> bookmark) {
for (Map.Entry<String, Long> entry : bookmark.entrySet()) {
if (!bookmarks.containsKey(entry.getKey()))
bookmarks.put(entry.getKey(), entry.getValue());
else {
long last = bookmarks.get(entry.getKey());
if (last < entry.getValue())
bookmarks.put(entry.getKey(), entry.getValue());
}
}
}
I want something with which there is always a simple object in the file, which is latest. I am even ok with going away from ObjectOutputStream.
I'm trying to serialize objects of big size in Java using Externalizable interface.
Code:
public class ResultsData implements Externalizable{
private static final long serialVersionUID = 1L;
private ArrayList<ALotOfResults1> results1;
private ArrayList<ALotOfResults2> results2;
private ArrayList<ALotOfResults3> results3;
private int selection;
public ResultsData(){
results1=new ArrayList<ALotOfResults1>();
results2=new ArrayList<ALotOfResults2>();
results3=new ArrayList<ALotOfResults3>();
}
//Getter and setter omited
#Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(results1);
out.writeObject(results2);
out.writeObject(results3);
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
switch(selection) {
case 0:
results1 = (ArrayList)in.readObject();
break;
case 1:
in.readObject();
results2 = (ArrayList)in.readObject();
break;
case 2:
in.readObject();
in.readObject();
results3 = (ArrayList)in.readObject();
break;
}
}
Those three arrayLists filled up during program execution have very big size (14 MB each one).
Code(load/save proccess):
public class ResultsManagement {
public static ResultsData loadResultsData(String path,ResultsData resultsData) {
try {
FileInputStream fisProd = new FileInputStream(path+".res");
ObjectInputStream oisProd = new ObjectInputStream(fisProd);
resultsData.readExternal(oisProd);
fisProd.close();
} catch (IOException ioe) {
System.out.println("Error de IO: " + ioe.getMessage());
} catch (ClassNotFoundException cnfe) {
System.out.println("Error de clase no encontrada: " + cnfe.getMessage());
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
return resultsData;
}
public static void saveResultsData(ResultsData resultsData,String path) {
try {
FileOutputStream fosProd = new FileOutputStream(path+".res");
ObjectOutputStream oosProd = new ObjectOutputStream(fosProd);
resultsData.writeExternal(oosProd);
fosProd.close();
} catch (IOException ioe) {
System.out.println("Error de IO: " + ioe.getMessage());
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
The unbreakable condition is that I want to have only one File, for example, Documents/Project/project1.res
How can I load some parts of the object without loading the other parts? Is it possible?
For example, I don't need to load the two first arrayList's (results1 and results2) when I only need to load the third one (results3), but the only way i know to get access to results3 is reading results1 and results2.
Code for the answer of Tinke:
In the ResultsData class:
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
return is.readObject();
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
byte[] r1 = serialize(results1);
System.out.println("Bytes in r1: "+r1.length);//42392 Bytes
out.write(r1);
byte[] r2 = serialize(results2);
System.out.println("Bytes in r2: "+r2.length);//19268558 Bytes (a lot of results here)
out.write(r2);
out.close();
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
switch(selection) {
case 0:
byte[] arrayBytes=new byte[42392];
in.read(arrayBytes);
results1 = (ArrayList)deserialize(arrayBytes);
break;
case 1:
in.skipBytes(42392);
byte[] arrayBytes2=new byte[19268558];
in.read(arrayBytes2);
results2 = (ArrayList)deserialize(arrayBytes2);
break;
}
}
As a generic solution, while inserting the data, insert the size (in bytes) of each list. then while reading, read the size in and skip those many bytes for each list you wish to skip. The solution could be optimized more depending on your use case and how you insert/access the data in the lists.