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.
Related
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 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));
}
}
for some reason, I'm in a situation where I need to use a property file like:
1=1
2=2
3=3
4=4
5=5
6=6
7=7
12=12
13=13
14=14
15=15
16=16
17=17
23=23
24=24
25=25
26=26
27=27
34=34
35=35
36=36
37=37
45=45
46=46
47=47
56=56
57=57
67=67
123=123
124=124
125=125
126=126
.................
24567=24567
34567=34567
123456=123456
123457=123457
123467=123467
123567=123567
124567=124567
134567=134567
234567=234567
1234567=1234567
And I have utility handler class to sort the keys
public class PropertyHandler {
private static PropertyHandler instance;
private Properties properties;
private PropertyHandler() {
InputStream fos = null;
try {
fos = PropertyHandler.class.getClassLoader().getResourceAsStream("dow-pattern.properties");
properties = new Properties() {
#Override
public Set<Object> keySet() {
return Collections.unmodifiableSet(new TreeSet<Object>(super.keySet()));
}
#Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(new TreeSet<Object>(super.keySet()));
}
};
properties.load(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static PropertyHandler getInstance() {
if (instance == null) {
instance = new PropertyHandler();
}
return instance;
}
private Properties getProperties() {
return properties;
}
public static String getStringProperty(String propertyName) {
return PropertyHandler.getInstance().getProperties().getProperty(propertyName);
}
public static int getIntProperty(String propertyName) {
return Integer.parseInt(PropertyHandler.getInstance().getProperties().getProperty(propertyName));
}
public static Set<Object> getAllKeys() {
return PropertyHandler.getInstance().getProperties().keySet();
}
}
But when I print the keys, by calling "getAllKeys()" the order of keys as not expected. It is printed in a random fashion.
1
12
123
1234
12345
123456
1234567
123457
12346
123467
12347
1235
12356
123567
12357
1236
........
Any pointers to solve this issue would be helpful.
That's not random, that's sorted alphabetically. You need to sort the values numerically. The easiest way would be converting the Strings to Integers before adding them to the TreeSet.
On my serialized XML File is only one attribute of my Object saved, although four should be saved. I think this is due to y XStream Object registering only one converter, although he should register four.
My Converters are all functioning individually. I tested them one by one.
My XML File:
<object-stream>
<model.Product>13</model.Product>
</object-stream>
My Product class which should be saved:
public class Product implements Externalizable, Serializable {
private static final long serialVersionUID = -8437751114305532162L;
#XStreamConverter(converter.NameConverter.class)
private SimpleStringProperty name;
#XStreamConverter(converter.PriceConverter.class)
private SimpleDoubleProperty price;
#XStreamConverter(converter.CountConverter.class)
private SimpleIntegerProperty quantity;
#XStreamConverter(converter.IDConverter.class)
private long id;
public Product(String name, int quantity, double price, long id)
{
this.name=new SimpleStringProperty(name);
this.quantity=new SimpleIntegerProperty(quantity);
this.price=new SimpleDoubleProperty(price);
this.id=id;
//Getter and Setter and implentation of Externalizable
My XStream class
XStream xstream;
ObjectInputStream ois;
ObjectOutputStream oos;
#Override
public void close() throws IOException {
if (oos != null) {
oos.close();
}
if (ois != null) {
ois.close();
}
}
#Override
public void writeObject(Product obj) throws IOException {
try {
oos.writeObject(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
public void open(InputStream input, OutputStream output) throws IOException {
xstream = createXStream(model.Product.class);
converter.ConverterManager con=new ConverterManager();
con.registerAllConverters(xstream);
if (input != null) {
if (input.available() > 0) {
ois = xstream.createObjectInputStream(input);
}
}
if (output != null) {
oos = xstream.createObjectOutputStream(output);
}
}
}
My ConverterManager:
import com.thoughtworks.xstream.XStream;
public class ConverterManager {
public void registerAllConverters(XStream xstream)
{
xstream.aliasAttribute("Product Price", "price");
xstream.registerConverter(new PriceConverter());
xstream.aliasAttribute("Product ID", "id");
xstream.registerConverter(new IDConverter());
xstream.aliasAttribute("Product Name", "name");
xstream.registerConverter(new NameConverter());
xstream.aliasAttribute("Product quantity", "quantity");
xstream.registerConverter(new CountConverter());
}
}
My writeObject, open and close methods are called from this method from another class:
private void saveModel() {
XStreamStrategy s=new XStreamStrategy();
try {
s.open(getFilePath());
} catch (IOException e) {
e.printStackTrace();
}
for(fpt.com.Product p: model)
{
try {
s.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}