I'm using Hazelcast as a shared map in my application. My map is like that:
Map<String, MyObject>
and MyObject:
class MyObject implements Serializeble {
// Map FieldName -> FieldValue
Map<String, Object> myMap;
}
So I'd like to use Hazelcast distributed query support to query in my object. I've checked that Hazelcast uses get's method to retrieve the object value, but in my case I don't have a get, instead of I'd like to implement my own getField like:
Object getField(String fieldName) {
return myMap[fieldName];
}
And force Hazelcast to call this method. As a workaround, I've hacked Hazelcast code to use a CustomGetter in the class
/hazelcast/src/main/java/com/hazelcast/query/impl/ReflectionHelper.java
line 144:
if (localGetter == null) {
localGetter = new CustomFieldGetter(name, obj);
}
and here My CustomFieldGetter class:
static class CustomFieldGetter extends Getter {
final Object value;
final Class type;
final String fieldName;
CustomFieldGetter(String fieldName, Object obj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
super(null);
this.fieldName = fieldName;
this.value = obj.getClass().getMethod("getField", String.class).invoke(obj, fieldName);
this.type = value.getClass();
}
#Override
Object getValue(Object obj) throws Exception {
return value;
}
#Override
Class getReturnType() {
return type;
}
#Override
boolean isCacheable() {
return false;
}
#Override
public String toString() {
return "FieldGetter [parent=" + parent + ", field=" + fieldName + "]";
}
}
Ok cool, after recompilation of Hazelcast, and using this new jar, I could reach queries using plain sql. But for pagingQueries I got some errors.
So my finally question is:
I'd like to avoid hack Hazelcast code (for further updates). Does Hazelcast has some supports on this issue? Is there any other solution for this problem?
PS: I'm using Hazelcast version -> hazelcast-3.3-RC3
Thanks in advance.
one option is to implement Portable interface. Then you could write each entry as a separate field. This assumes the entry value implements the Portable interface as well.
Look at the sample code how to use Portable.
Related
I am attempting to deserialize a jackson-serialized Google Ads sdk object. In particular, I am running into issues in instantiating specific classes which behave like enums, for example :
public class CampaignStatus implements Serializable {
private String _value_;
private static HashMap _table_ = new HashMap();
public static final String _UNKNOWN = "UNKNOWN";
public static final String _ENABLED = "ENABLED";
public static final String _PAUSED = "PAUSED";
public static final String _REMOVED = "REMOVED";
public static final CampaignStatus UNKNOWN = new CampaignStatus("UNKNOWN");
public static final CampaignStatus ENABLED = new CampaignStatus("ENABLED");
public static final CampaignStatus PAUSED = new CampaignStatus("PAUSED");
public static final CampaignStatus REMOVED = new CampaignStatus("REMOVED");
private static TypeDesc typeDesc = new TypeDesc(CampaignStatus.class);
protected CampaignStatus(String value) {
this._value_ = value;
_table_.put(this._value_, this);
}
public String getValue() {
return this._value_;
}
public static CampaignStatus fromValue(String value) throws IllegalArgumentException {
CampaignStatus enumeration = (CampaignStatus)_table_.get(value);
if (enumeration == null) {
throw new IllegalArgumentException();
} else {
return enumeration;
}
}
public static CampaignStatus fromString(String value) throws IllegalArgumentException {
return fromValue(value);
}
public boolean equals(Object obj) {
return obj == this;
}
public int hashCode() {
return this.toString().hashCode();
}
public String toString() {
return this._value_;
}
public Object readResolve() throws ObjectStreamException {
return fromValue(this._value_);
}
public static Serializer getSerializer(String mechType, Class _javaType, QName _xmlType) {
return new EnumSerializer(_javaType, _xmlType);
}
public static Deserializer getDeserializer(String mechType, Class _javaType, QName _xmlType) {
return new EnumDeserializer(_javaType, _xmlType);
}
public static TypeDesc getTypeDesc() {
return typeDesc;
}
static {
typeDesc.setXmlType(new QName("https://adwords.google.com/api/adwords/cm/v201809", "CampaignStatus"));
}
}
When a Campaign object is serialized (which contains a CampaignStatus as defined above), the JSON looks like this:
"status":{"value":"ENABLED"}
The deserializer throws a mismatched input exception when trying to write a JSON campaign to a Campaign object. Since the objects are owned by Google, I can't modify the existing classes or add annotations. My solution needs to work for 250+ classes that follow this pattern, so individually wrapping or extending these isn't a feasible solution. Additionally, I will have many different stakeholders serializing these objects, so modifying how they are serialized is also not a useable solution.
What I need is some way to indicate to the deserializer that when it comes across a situation like this, it should look for the fromValue method and use that. I'm ok with explicitly stating what json keys/values would need to use such a method; I just need a more dynamic way of modifying the serialization than extending the class or adding annotations.
You can indicate factory method using #JsonCreator annotation - it is going to be used by Jackson to perform deserialization.
In your case it would look something like this:
#JsonCreator
public static CampaignStatus fromValue(#JsonProperty("value") String value) throws IllegalArgumentException {
CampaignStatus enumeration = (CampaignStatus)_table_.get(value);
if (enumeration == null) {
throw new IllegalArgumentException();
} else {
return enumeration;
}
}
I am a bit confused with what exactly you are trying to achieve but feel free to put any logic that fulfill you requirements in the method above.
So I didn't find the best possible solution, but I'll share the best I could come up with. I implemented a new generic deserializer extending JsonDeserializer, and used reflection in the deserialize method to invoke the .fromValue method. I then used reflection to search the directories for all classes, and search each class for a matching .fromValue method. Every time I successfully find a class that follows this pattern, I register it with the mapper using a new generic deserializer for the corresponding class. It's a bit costly, but I only register the deserializers at instantiation so it's ok that it's a complex.
I am stuck at converting Java Bean to Map. There are many resources on the internet, but unfortunately they all treat converting simple beans to Maps. My ones are a little bit more extensive.
There's simplified example:
public class MyBean {
private String firstName;
private String lastName;
private MyHomeAddress homeAddress;
private int age;
// getters & setters
}
My point is to produce Map<String, Object> which, in this case, is true for following conditions:
map.containsKey("firstName")
map.containsKey("lastName")
map.containsKey("homeAddress.street") // street is String
map.containsKey("homeAddress.number") // number is int
map.containsKey("homeAddress.city") // city is String
map.containsKey("homeAddress.zipcode") // zipcode is String
map.containsKey("age")
I have tried using Apache Commons BeanUtils. Both approaches BeanUtils#describe(Object) and BeanMap(Object) produce a Map which "deep level" is 1 (I mean that there's only "homeAddress" key, holding MyHomeAddress object as a value). My method should enter the objects deeper and deeper until it meets a primitive type (or String), then it should stop digging and insert key i.e. "order.customer.contactInfo.home".
So, my question is: how can it be easliy done (or is there already existing project which would allow me to do that)?
update
I have expanded Radiodef answer to include also Collections, Maps Arrays and Enums:
private static boolean isValue(Object value) {
final Class<?> clazz = value.getClass();
if (value == null ||
valueClasses.contains(clazz) ||
Collection.class.isAssignableFrom(clazz) ||
Map.class.isAssignableFrom(clazz) ||
value.getClass().isArray() ||
value.getClass().isEnum()) {
return true;
}
return false;
}
Here's a simple reflective/recursive example.
You should be aware that there are some issues with doing a conversion the way you've asked:
Map keys must be unique.
Java allows classes to name their private fields the same name as a private field owned by an inherited class.
This example doesn't address those because I'm not sure how you want to account for them (if you do). If your beans inherit from something other than Object, you will need to change your idea a little bit. This example only considers the fields of the subclass.
In other words, if you have
public class SubBean extends Bean {
this example will only return fields from SubBean.
Java lets us do this:
package com.acme.util;
public class Bean {
private int value;
}
package com.acme.misc;
public class Bean extends com.acme.util.Bean {
private int value;
}
Not that anybody should be doing that, but it's a problem if you want to use String as the keys, because there would be two keys named "value".
import java.lang.reflect.*;
import java.util.*;
public final class BeanFlattener {
private BeanFlattener() {}
public static Map<String, Object> deepToMap(Object bean) {
Map<String, Object> map = new LinkedHashMap<>();
try {
putValues(bean, map, null);
} catch (IllegalAccessException x) {
throw new IllegalArgumentException(x);
}
return map;
}
private static void putValues(Object bean,
Map<String, Object> map,
String prefix)
throws IllegalAccessException {
Class<?> cls = bean.getClass();
for (Field field : cls.getDeclaredFields()) {
if (field.isSynthetic() || Modifier.isStatic(field.getModifiers()))
continue;
field.setAccessible(true);
Object value = field.get(bean);
String key;
if (prefix == null) {
key = field.getName();
} else {
key = prefix + "." + field.getName();
}
if (isValue(value)) {
map.put(key, value);
} else {
putValues(value, map, key);
}
}
}
private static final Set<Class<?>> VALUE_CLASSES =
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
Object.class, String.class, Boolean.class,
Character.class, Byte.class, Short.class,
Integer.class, Long.class, Float.class,
Double.class
// etc.
)));
private static boolean isValue(Object value) {
return value == null
|| value instanceof Enum<?>
|| VALUE_CLASSES.contains(value.getClass());
}
}
You could always use the Jackson Json Processor. Like this:
import com.fasterxml.jackson.databind.ObjectMapper;
//...
ObjectMapper objectMapper = new ObjectMapper();
//...
#SuppressWarnings("unchecked")
Map<String, Object> map = objectMapper.convertValue(pojo, Map.class);
where pojo is some Java bean. You can use some nice annotations on the bean to control the serialization.
You can re-use the ObjectMapper.
I have some Data Objects e.g. Task, Resource etc.
These Objects hold domain data e.g.
public class Task{
private int Id;
private String taskName;
.......
//getters and setters here
//in addition they have a special method dynamically to get values i.e. There is a reason for this
public static String runGetter(Task task, String getter) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (Method method : task.getClass().getMethods()) {
if (method.getName().toLowerCase().equalsIgnoreCase(getter.toLowerCase())) {
if (method.getReturnType().isPrimitive()) {
StringBuilder sb = new StringBuilder();
sb.append(method.invoke(task));
return sb.toString();
}
if (method.invoke(task) != null) {
return method.invoke(task).toString();
}
}
}
return null;
}
}
}
Now I have some methods that take these objects and write them out to streams
e.g.
public class WriterUtil{
public void write(Task task, File outputFile){
//write the task object out.
}
public void write(Resource resource, File outputFile){
//write the resource object out
}
....
}
The write methods call another method to get data out of the object as follows. (Yes, it can be made more efficient but it is not the core of my problem)
public class WriterUtil {
.....
public static String extractLine(Task task, LinkedHashMap<String, String> columns, String delimiter) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
StringBuilder sb = new StringBuilder();
Iterator<String> itr = columns.keySet().iterator();
while (itr.hasNext()) {
String getter = "get" + itr.next();
String value = Task.runGetter(task, getter);
if (value == null)
value = "";
sb.append(value + delimiter + " ");
}
return sb.toString().substring(0, sb.lastIndexOf(delimiter)).trim();
}
......
}
My Main problem is this given the described scenario above, I find myself writing the same identical code for each domain object e.g.
public void write(Task task, File outputFile)
public void write(Resource resource, File outputFile)
//etc ....
I repeat the same for extractLine.
As you can see I am duplicating the same code for each domain object. Where the only thing varying is the actual domain object. These methods do the exact same thing with each domain object.
My Question is; if I am to refactor these methods and write one method each to apply to every domain object, what are my best options.
Should I have the domain objects implement an interface? This seems rather cumbersome and I am not sure it is the right course of action.
Can I use generics? I expect it is probably the best practice but I have very limited experience with how to go about generifying (Is that a word?) my Domain Objects and these common methods. Can someone offer a re-write of my above code on how they would modify them for generic?
Do I have a third option?
Move the reflection code into a utility type and change the signature to:
public static String runGetter(Object bean, String getter)
The Task type isn't used at all inside the method.
Likewise, the only reason you need a Task type here is because the other call requires it:
public static String extractLine(Object bean, Map<String, String> columns,
String delimiter)
You'll need to use an interface; generics can't be employed here (you could do it in C++ with templates, but not in Java).
If you don't want you objects to implement the interface, you can create helper objects for each of your domain classes; those helper objects would implement an interface with the extractLine() function:
class TaskExtractLine implements IExtractLine
{
public TaskExtractLine(Task task)
{
this.task = task;
}
public String extractLine(LinkedHashMap<String, String> columns, String delimiter)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
return WriterUtil.extractLine(task, columns, delimiter);
}
private Task task;
}
Then you'll have the write function like this: public void write(IExtractLine extractLineHelper, File outputFile) and call it like this: write(new TaskExtractLine(task), outputFile).
A little background as to what I'm trying to achieve:
I'm parsing JSON (over 15GB) and I must store it in memory so any wrappers and extra data is not welcomed, due to the framework and interfaces used within it I must provide functionality to access fields by name. By replacing some String with Enum, Integer with int, Double with double, etc. I'm able to shave about 90% of memory footprint (in comparison with Jackson).
I'm looking to efficiently access the fields at runtime in Java by their name. I'm aware of reflection, but for my case its performance is simply unacceptable, so I don't want to use it.
If it makes the problem easier to solve I'm not too bothered about setting the fields values. I also know at compile time the names of supported fields.
I don't want to store everything in a map i.e. Map<String,Object> due to the memory footprint of boxed object, but I don't mind returning them in a boxed form.
I'm sure this problem was encountered by others and I'm interested in any clever solutions - cleverer than tons of if ... else ... statements.
Let's say the interface to implement is:
public interface Accessor {
Object get(String fieldName);
}
The Object returned by get can be of any type including enum. A naive implementation would be:
public class TestObject implements Accessor {
public enum MyEnum {ONE, TWO, THREE};
private final MyEnum myEnum;
private final int myInt;
private final double myDouble;
private final String myString;
public TestObject(MyEnum myEnum, int myInt, double myDouble, String myString) {
this.myEnum = myEnum;
this.myInt = myInt;
this.myDouble = myDouble;
this.myString = myString;
}
#Override
public Object get(String fieldName) {
if ("myEnum".equals(fieldName)) {
return myEnum;
} else if ("myInt".equals(fieldName)) {
return myInt;
} else if ("myDouble".equals(fieldName)) {
return myDouble;
} else if ("myString".equals(fieldName)) {
return myString;
} else {
throw new UnsupportedOperationException(); // Or could simply return null
}
}
}
What you want is a mapping from a fieldName to a value, the type of which is determined by the fieldName. You know the set of field names up-front, so this is an ideal task for an Enum.
If you don't like the idea of hard-coding each field as an enum, then the variation would be an enum-per-type (MY_FIELD1 becomes MY_ENUM), with a mapping from fieldName to this EnumType.
In the code below I'm making assumptions about the relationship between fieldName and TestObject. Specifically it looks like TestObject is presenting various types of the same value (surely where reasonable), as opposed to a separate value for each field name?
So, to the code:
Rewrite:
#Override
public Object get(String fieldName) {
MyField field = MyField.mapNameToField(fieldName);
if (field == null)
throw new UnsupportedOperationException(); // Or could simply return null
return field.getValue(this);
}
Given (something like):
enum MyField {
MY_FIELD1("myField1") {
public Object getValue(TestObject obj) { return obj.myEnum; }
},
MY_FIELD2("myField2") {
public Object getValue(TestObject obj) { return obj.myInt; }
},
...
;
public abstract Object getValue(TestObject obj);
public String getName() { return name; }
public static MyField mapNameToField(String name) { return map.get(name); }
static {
map = new HashMap<String,MyField>();
for(MyField value: values()) {
map.put(value.getName(), value);
}
}
private MyField(String fieldName) { name = fieldName; }
private String name;
private static Map<String, MyField> map;
}
I've never used this, but looks promising:
http://labs.carrotsearch.com/download/hppc/0.4.1/api/
"High Performance Primitive Collections (HPPC) library provides typical data structures (lists, stacks, maps) template-generated for all Java primitive types (byte, int, etc.) to conserve memory and boost performance."
In particular, the Object{Type}OpenHashMap classes might be what you're looking for:
ObjectByteOpenHashMap
ObjectCharOpenHashMap
ObjectDoubleOpenHashMap
ObjectFloatOpenHashMap
ObjectIntOpenHashMap
ObjectLongOpenHashMap
ObjectShortOpenHashMap
I imagine you would have all 7 of these defined as fields (or whatever subset of them you like), and you would probe each one in turn to see if the key was present for that type of primitive value. E.g.,
if (byteMap.containsKey(key)) {
return byteMap.lget(); // last value saved in a call to containsKey()
} else if (charMap.containsKey(key)) {
return charMap.lget();
} else if {
// and so on...
}
Notice they have their own special lget() method call to optimize the containsKey() / get() usage pattern so typical with maps.
I've been struggling with this for a while and have yet to find an answer. As a result, my brain is somewhat muddled, so pardon me if I make a dumb mistake.
I'm trying to implement a typed INI parser, that will parse this kind of file:
[section1]
<int>intkey=0
<float>floatkey=0.0
<str>stringkey=test
[section2]
<float>x=1.0
<float>y=1.0
<float>z=0.0
In doing so, I have a central class named Config, which handles the basic reading and writing operations. One of the methods of Config is called get(String section, String key), which ideally would return a value appropriate for the requested section-key pair, like so:
Config cfg = new Config("test.ini");
cfg.get("section2", "x"); // 1.0, not "1.0" or some Object that technically represents the float
cfg.get("section1", "intkey"); // 0
cfg.get("section1", "strkey"); // "test"
I'm currently using an enum to handle the conversion of the String to various types, with an abstract method overridden by the different types:
enum Type
{
INTEGER ("int") {
public Object parse(String value) {
try
{
return Integer.parseInt(value);
} catch (NumberFormatException e)
{
return null;
}
}
},
FLOAT ("float") {
public Object parse(String value) {
try
{
return Float.parseFloat(value);
} catch (NumberFormatException e)
{
return null;
}
}
},
STRING ("str") {
public Object parse(String value) {
return value;
}
};
public final String name;
Type(String name)
{
this.name = name;
}
private static HashMap<String, Type> configMap = generateConfigMap();
private static HashMap<String, Type> generateConfigMap()
{
HashMap<String, Type> map = new HashMap<String, Type>();
for (Type type : Type.values())
map.put(type.name, type);
return map;
}
public static Type get(String name)
{
return configMap.get(name);
}
abstract public Object parse(String value);
}
Unfortunately, parse(String value) returns an Object, and when passed out of Config, requires a cast or similar, and ideally this would be self-contained.
If I'm going about this completely wrong and there's a more flexible or simple way to code it, please let me know. I'm open to suggestions. Though I would like to know if there's a way to do this. Maybe with generics...?
Note: I know I'm missing imports and the like. That's not why I'm posting here.
Here's the thing. If the code that calls config.get() doesn't know what type to expect, you can't possibly return anything other than Object since the calling code doesn't know what to expect. Of course you'll have to cast.
Now, if you wanted to design Config in a way that the caller did know what type it was asking for, than that becomes a bit easier. The easiest approach then is to do something like this:
public class Config {
public int getInt(String a, String b) {
return ((Integer)get(a, b)).intValue();
}
}
But until the caller knows what to expect, you really gain nothing from avoiding casts.
If you want to return a a type of object depending on what you get you can do this:
public <T extends MyObject> T myMethod(Class<T> type) {
return type.cast(myObj);
}