How to deserialize beans given in a java properties file? - java

Please, consider the following piece of a typical VMWare configuration file (*.vmx):
memsize = "2048"
MemTrimRate = "-1"
mks.enable3d = "TRUE"
nvram = "Windows Server 2003 Standard Edition.nvram"
pciBridge0.pciSlotNumber = "17"
pciBridge0.present = "TRUE"
pciBridge4.functions = "8"
pciBridge4.pciSlotNumber = "18"
pciBridge4.present = "TRUE"
pciBridge4.virtualDev = "pcieRootPort"
pciBridge5.functions = "8"
pciBridge5.pciSlotNumber = "19"
pciBridge5.present = "TRUE"
pciBridge5.virtualDev = "pcieRootPort"
pciBridge6.functions = "8"
pciBridge6.pciSlotNumber = "20"
pciBridge6.present = "TRUE"
pciBridge6.virtualDev = "pcieRootPort"
pciBridge7.functions = "8"
pciBridge7.pciSlotNumber = "32"
pciBridge7.present = "TRUE"
pciBridge7.virtualDev = "pcieRootPort"
replay.filename = ""
replay.supported = "FALSE"
roamingVM.exitBehavior = "go"
By observing this configuration, one can imagine a PciBridge java bean type with the following signature:
class PciBridge
{
public int pciSlotNumber; // or public int getPciSlotNumber(){...} and public void setPciSlotNumber(int v){...}
public boolean present; // or get/is/set methods
public int functions; // or get/set methods
public String virtualDev; // or get/set methods
}
Moreover, the configuration manager responsible for reading the vmx files might expose the following method:
public <T> List<T> getObjects(final String prop, Class<T> clazz);
And then given the aforementioned configuration, invoking getObjects("pciBridge", PciBridge.class) would return a list of all the PciBridge objects specified in the configuration - the total of 5 in our case.
How do I implement this functionality? Of course, I have seen the same pattern in several different products, so I figure there should be something ready out there to implement this functionality.
Any ideas?
Thanks.
EDIT
Correction - I do not claim that VMWare utilizes the java properties file format (the double quotes are redundant), but the spirit is the same. Besides, there are proper Java applications utilizing the same pattern.

I am posting my own solution. The code depends on http://commons.apache.org/beanutils/ to reflect on the beans and on http://commons.apache.org/configuration/ to manage the property based configuration (because it supports property references using the ${} syntax).
public static <T> Collection<T> getBeans(String prop, Class<T> clazz) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Pattern pattern = Pattern.compile("^" + prop.replace(".", "\\.") + "(\\d*)\\.(\\w+)$");
Map<String, T> beans = new TreeMap<String, T>();
#SuppressWarnings("rawtypes")
Map description = null;
T tmpBean = null;
Iterator<String> itKeys = m_propStore.getKeys();
while (itKeys.hasNext()) {
String key = itKeys.next();
Matcher matcher = pattern.matcher(key);
boolean matchFound = matcher.find();
if (matchFound) {
if (description == null) {
tmpBean = clazz.newInstance();
description = BeanUtils.describe(tmpBean);
}
String beanPropName = matcher.group(2);
if (description.containsKey(beanPropName)) {
String beanKey = matcher.group(1);
T bean = beans.get(beanKey);
if (bean == null) {
bean = tmpBean == null ? clazz.newInstance() : tmpBean;
tmpBean = null;
beans.put(beanKey, bean);
}
try {
BeanUtils.setProperty(bean, beanPropName, m_propStore.getString(key));
} catch (Exception e) {
m_logger.error(String.format("[SystemConfiguration]: failed to set the %s.%s bean property to the value of the %s configuration property - %s",
bean.getClass().getName(), beanPropName, key, e.getMessage()));
}
}
}
}
return beans.values();
}

Related

How to access an object attribute from a String in Java?

I have a String that tells me what attribute I should use to make some filtering. How can I use this String to actually access the data in the object ?
I have a method that returns a List of strings telling me how to filter my List of objects. Such as:
String[] { "id=123", "name=foo" }
So my first idea was to split the String into 2 parts with:
filterString.split("=") and use the first part of the String (e.g. "id") to identify the attribute being filtered.
Coming for a JS background, I would do it like this:
const attr = filterString.split('=')[0]; // grabs the "id" part from the string "id=123", for example
const filteredValue = filterString.split('=')[1]; // grabs the "123" part from the string "id=123", for example
items.filter(el => el[`${attr}`] === filteredValue) // returns an array with the items where the id == "123"
How would I be able to do that with Java ?
You can use reflections to get fields of class by dynamic name.
#Test
void test() throws NoSuchFieldException, IllegalAccessException {
String[] filters = {"id=123", "name=foo"};
List<Item> list = newArrayList(new Item(123, "abc"), new Item(2, "foo"), new Item(123, "foo"));
Class<Item> itemClass = Item.class;
for (String filter : filters) {
String key = StringUtils.substringBefore(filter, "=");
String value = StringUtils.substringAfter(filter, "=");
Iterator<Item> iterator = list.iterator();
while (iterator.hasNext()) {
Item item = iterator.next();
Field field = itemClass.getDeclaredField(key);
field.setAccessible(true);
Object itemValue = field.get(item);
if (!value.equals(String.valueOf(itemValue))) {
iterator.remove();
}
}
}
assertEquals(1, list.size());
}
But I agree with comment from sp00m - it's slow and potentially dangerous.
This code should work :
//create the filter map
Map<String, String> expectedFieldValueMap = new HashMap<>();
for (String currentDataValue : input) {
String[] keyValue = currentDataValue.split("=");
String expectedField = keyValue[0];
String expectedValue = keyValue[1];
expectedFieldValueMap.put(expectedField, expectedValue);
}
Then iterate over input object list ( have used Employee class with id and name fields & prepared a test data list with few Employee objects called inputEmployeeList which is being iterated ) and see if all filters passes, using reflection, though slow, is one way:
for (Employee e : inputEmployeeList) {
try {
boolean filterPassed = true;
for (String expectedField : expectedFieldValueMap.keySet()) {
String expectedValue = expectedFieldValueMap.get(expectedField);
Field fieldData = e.getClass().getDeclaredField(expectedField);
fieldData.setAccessible(true);
if (!expectedValue.equals(fieldData.get(e))) {
filterPassed = false;
break;
}
}
if (filterPassed) {
System.out.println(e + " object passed the filter");
}
} catch (Exception any) {
any.printStackTrace();
// handle
}
}

How to convert protocol-buffer message to a HashMap in java?

I have a protobuf message of the form
enum PolicyValidationType {
Number = 0;
}
message NumberPolicyValidation {
optional int64 maxValue = 1;
optional int64 minValue = 2;
}
message PolicyObject {
required string key = 1;
optional string value = 2;
optional string name = 3;
optional PolicyValidationType validationType = 4;
optional NumberPolicyValidation numberPolicyValidation = 5;
}
For example
policyObject {
key: "sessionIdleTimeoutInSecs"
value: "1800"
name: "Session Idle Timeout"
validationType: Number
numberPolicyValidation {
maxValue: 3600
minValue: 5
}
}
Can someone let me know how can I convert this to a Map like below:-
{validationType=Number, name=Session Idle Timeout, numberPolicyValidation={maxValue=3600.0, minValue=5.0}, value=1800, key=sessionIdleTimeoutInSecs}
One way I can think of is convert this to a json and then convert the json to map?
PolicyObject policyObject;
...
JsonFormat jsonFormat = new JsonFormat();
final String s = jsonFormat.printToString(policyObject);
Type objectMapType = new TypeToken<HashMap<String, Object>>() {}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<HashMap<String,Object>>(){}.getType(), new PrimitiveDeserializer()).create();
Map<String, Object> mappedObject = gson.fromJson(s, objectMapType);
I think there must be some better way. Can someone suggest any better approach?
I created small dedicated class to generically convert any Google protocol buffer message into a Java Map.
public class ProtoUtil {
#NotNull
public Map<String, Object> protoToMap(Message proto) {
final Map<Descriptors.FieldDescriptor, Object> allFields = proto.getAllFields();
Map<String, Object> map = new LinkedHashMap<>();
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : allFields.entrySet()) {
final Descriptors.FieldDescriptor fieldDescriptor = entry.getKey();
final Object requestVal = entry.getValue();
final Object mapVal = convertVal(proto, fieldDescriptor, requestVal);
if (mapVal != null) {
final String fieldName = fieldDescriptor.getName();
map.put(fieldName, mapVal);
}
}
return map;
}
#Nullable
/*package*/ Object convertVal(#NotNull Message proto, #NotNull Descriptors.FieldDescriptor fieldDescriptor, #Nullable Object protoVal) {
Object result = null;
if (protoVal != null) {
if (fieldDescriptor.isRepeated()) {
if (proto.getRepeatedFieldCount(fieldDescriptor) > 0) {
final List originals = (List) protoVal;
final List copies = new ArrayList(originals.size());
for (Object original : originals) {
copies.add(convertAtomicVal(fieldDescriptor, original));
}
result = copies;
}
} else {
result = convertAtomicVal(fieldDescriptor, protoVal);
}
}
return result;
}
#Nullable
/*package*/ Object convertAtomicVal(#NotNull Descriptors.FieldDescriptor fieldDescriptor, #Nullable Object protoVal) {
Object result = null;
if (protoVal != null) {
switch (fieldDescriptor.getJavaType()) {
case INT:
case LONG:
case FLOAT:
case DOUBLE:
case BOOLEAN:
case STRING:
result = protoVal;
break;
case BYTE_STRING:
case ENUM:
result = protoVal.toString();
break;
case MESSAGE:
result = protoToMap((Message) protoVal);
break;
}
}
return result;
}
}
Hope that helps! Share and enjoy.
Be aware that both approaches described above (serialize/deserialize by tuk and custom converter by Zarnuk) will produce different outputs.
With the serialize/deserialize approach:
Field names in snake_case format will be automatically converted into camelCase. JsonFormat.printer() does this.
Numeric values will be converted to float. Gson does that for you.
Values of type Duration will be converted into strings with format durationInseconds + "s", i.e. "30s" for a duration of 30 seconds and "0.000500s" for a duration of 500,000 nanoseconds. JsonFormat.printer() does this.
With the custom converter approach:
Field names will remain as they are described on the proto file.
Integers and floats will keep their own type.
Values of type Duration will become objects with their corresponding fields.
To show the differences, here is a comparison of the outcomes of both approaches.
Original message (here is the proto file):
method_config {
name {
service: "helloworld.Greeter"
method: "SayHello"
}
retry_policy {
max_attempts: 5
initial_backoff {
nanos: 500000
}
max_backoff {
seconds: 30
}
backoff_multiplier: 2.0
retryable_status_codes: UNAVAILABLE
}
}
With the serialize/deserialize approach:
{
methodConfig=[ // field name was converted to cameCase
{
name=[
{
service=helloworld.Greeter,
method=SayHello
}
],
retryPolicy={
maxAttempts=5.0, // was integer originally
initialBackoff=0.000500s, // was Duration originally
maxBackoff=30s, // was Duration originally
backoffMultiplier=2.0,
retryableStatusCodes=[
UNAVAILABLE
]
}
}
]
}
With the custom converter approach:
{
method_config=[ // field names keep their snake_case format
{
name=[
{
service=helloworld.Greeter,
method=SayHello
}
],
retry_policy={
max_attempts=5, // Integers stay the same
initial_backoff={ // Duration values remains an object
nanos=500000
},
max_backoff={
seconds=30
},
backoff_multiplier=2.0,
retryable_status_codes=[
UNAVAILABLE
]
}
}
]
}
Bottom line
So which approach is better?
Well, it depends on what you are trying to do with the Map<String, ?>. In my case, I was configuring a grpc client to be retriable, which is done via ManagedChannelBuilder.defaultServiceConfig API. The API accepts a Map<String, ?> with this format.
After several trials and errors, I figured that the defaultServiceConfig API assumes you are using GSON, hence the serialize/deserialize approach worked for me.
One more advantage of the serialize/deserialize approach is that the Map<String, ?> can be easily converted back to the original protobuf value by serializing it back to json, then using the JsonFormat.parser() to obtain the protobuf object:
ServiceConfig original;
...
String asJson = JsonFormat.printer().print(original);
Map<String, ?> asMap = new Gson().fromJson(asJson, Map.class);
// Convert back to ServiceConfig
String backToJson = new Gson().toJson(asMap);
ServiceConfig.Builder builder = ServiceConfig.newBuilder();
JsonFormat.parser().merge(backToJson, builder);
ServiceConfig backToOriginal = builder.build();
... whereas the custom converter approach method doesn't have an easy way to convert back as you need to write a function to convert the map back to the original proto by navigating the tree.

Java + MongoDB: how get a nested field value using complete path?

I have this path for a MongoDB field main.inner.leaf and every field couldn't be present.
In Java I should write, avoiding null:
String leaf = "";
if (document.get("main") != null &&
document.get("main", Document.class).get("inner") != null) {
leaf = document.get("main", Document.class)
.get("inner", Document.class).getString("leaf");
}
In this simple example I set only 3 levels: main, inner and leaf but my documents are deeper.
So is there a way avoiding me writing all these null checks?
Like this:
String leaf = document.getString("main.inner.leaf", "");
// "" is the deafult value if one of the levels doesn't exist
Or using a third party library:
String leaf = DocumentUtils.getNullCheck("main.inner.leaf", "", document);
Many thanks.
Since the intermediate attributes are optional you really have to access the leaf value in a null safe manner.
You could do this yourself using an approach like ...
if (document.containsKey("main")) {
Document _main = document.get("main", Document.class);
if (_main.containsKey("inner")) {
Document _inner = _main.get("inner", Document.class);
if (_inner.containsKey("leaf")) {
leafValue = _inner.getString("leaf");
}
}
}
Note: this could be wrapped up in a utility to make it more user friendly.
Or use a thirdparty library such as Commons BeanUtils.
But, you cannot avoid null safe checks since the document structure is such that the intermediate levels might be null. All you can do is to ease the burden of handling the null safety.
Here's an example test case showing both approaches:
#Test
public void readNestedDocumentsWithNullSafety() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Document inner = new Document("leaf", "leafValue");
Document main = new Document("inner", inner);
Document fullyPopulatedDoc = new Document("main", main);
assertThat(extractLeafValueManually(fullyPopulatedDoc), is("leafValue"));
assertThat(extractLeafValueUsingThirdPartyLibrary(fullyPopulatedDoc, "main.inner.leaf", ""), is("leafValue"));
Document emptyPopulatedDoc = new Document();
assertThat(extractLeafValueManually(emptyPopulatedDoc), is(""));
assertThat(extractLeafValueUsingThirdPartyLibrary(emptyPopulatedDoc, "main.inner.leaf", ""), is(""));
Document emptyInner = new Document();
Document partiallyPopulatedMain = new Document("inner", emptyInner);
Document partiallyPopulatedDoc = new Document("main", partiallyPopulatedMain);
assertThat(extractLeafValueManually(partiallyPopulatedDoc), is(""));
assertThat(extractLeafValueUsingThirdPartyLibrary(partiallyPopulatedDoc, "main.inner.leaf", ""), is(""));
}
private String extractLeafValueUsingThirdPartyLibrary(Document document, String path, String defaultValue) {
try {
Object value = PropertyUtils.getNestedProperty(document, path);
return value == null ? defaultValue : value.toString();
} catch (Exception ex) {
return defaultValue;
}
}
private String extractLeafValueManually(Document document) {
Document inner = getOrDefault(getOrDefault(document, "main"), "inner");
return inner.get("leaf", "");
}
private Document getOrDefault(Document document, String key) {
if (document.containsKey(key)) {
return document.get(key, Document.class);
} else {
return new Document();
}
}

Using ScriptEngine in java, How can I extract function list?

using Jsoup, I extract JavaScript part in html file. and store it as java String Object.
and I want to extract function list, variables list in js's function using javax.script.ScriptEngine
JavaScript part has several function section.
ex)
function a() {
var a_1;
var a_2
...
}
function b() {
var b_1;
var b_2;
...
}
function c() {
var c_1;
var c_2;
...
}
My Goals is right below.
List funcList
a
b
c
List varListA
a_1
a_2
...
List varListB
b_1
b_2
...
List varListC
c_1
c_2
...
How can I extract function list and variables list(or maybe values)?
I think you can do this by using javascript introspection after having loaded the javascript in the Engine - e.g. for functions:
ScriptEngine engine;
// create the engine and have it load your javascript
Bindings bind = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Set<String> allAttributes = bind.keySet();
Set<String> allFunctions = new HashSet<String>();
for ( String attr : allAttributes ) {
if ( "function".equals( engine.eval("typeof " + attr) ) ) {
allFunctions.add(attr);
}
}
System.out.println(allFunctions);
I haven't found a way to extract the variables inside functions (local variables) without delving in internal mechanics (and thus unsafe to use) of the javascript scripting engine.
It is pretty tricky. ScriptEngine API seems not good for inspecting the code. So, I have such kind of pretty ugly solution with instance of and cast operators.
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
for (Map.Entry<String, Object> scopeEntry : bindings.entrySet()) {
Object value = scopeEntry.getValue();
String name = scopeEntry.getKey();
if (value instanceof NativeFunction) {
log.info("Function -> " + name);
NativeFunction function = NativeFunction.class.cast(value);
DebuggableScript debuggableFunction = function.getDebuggableView();
for (int i = 0; i < debuggableFunction.getParamAndVarCount(); i++) {
log.info("First level arg: " + debuggableFunction.getParamOrVarName(i));
}
} else if (value instanceof Undefined
|| value instanceof String
|| value instanceof Number) {
log.info("Global arg -> " + name);
}
}
I had similar issue. Maybe it will be helpfull for others.
I use groove as script lang. My Task was to retrive all invokable functions from the script. And then filter this functions by some criteria.
Unfortunately this approach is usefull only for groovy...
Get script engine:
public ScriptEngine getEngine() throws Exception {
if (engine == null)
engine = new ScriptEngineManager().getEngineByName(scriptType);
if (engine == null)
throw new Exception("Could not find implementation of " + scriptType);
return engine;
}
Compile and evaluate script:
public void evaluateScript(String script) throws Exception {
Bindings bindings = getEngine().getBindings(ScriptContext.ENGINE_SCOPE);
bindings.putAll(binding);
try {
if (engine instanceof Compilable)
compiledScript = ((Compilable)getEngine()).compile(script);
getEngine().eval(script);
} catch (Throwable e) {
e.printStackTrace();
}
}
Get functions from script. I did not found other ways how to get all invokable methods from script except Reflection. Yeah, i know that this approach depends on ScriptEngine implementation, but it's the only one :)
public List getInvokableList() throws ScriptException {
List list = new ArrayList();
try {
Class compiledClass = compiledScript.getClass();
Field clasz = compiledClass.getDeclaredField("clasz");
clasz.setAccessible(true);
Class scrClass = (Class)clasz.get(compiledScript);
Method[] methods = scrClass.getDeclaredMethods();
clasz.setAccessible(false);
for (int i = 0, j = methods.length; i < j; i++) {
Annotation[] annotations = methods[i].getDeclaredAnnotations();
boolean ok = false;
for (int k = 0, m = annotations.length; k < m; k++) {
ok = annotations[k] instanceof CalculatedField;
if (ok) break;
}
if (ok)
list.add(methods[i].getName());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
}
return list;
}
In my task i don't need all functions, for this i create custom annotation and use it in the script:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CalculatedField {
}
Script example:
import com.vssk.CalculatedField;
def utilFunc(s) {
s
}
#CalculatedField
def func3() {
utilFunc('Testing func from groovy')
}
Method to invoke script function by it's name:
public Object executeFunc(String name) throws Exception {
return ((Invocable)getEngine()).invokeFunction(name);
}

Java toString() using reflection?

I was writing a toString() for a class in Java the other day by manually writing out each element of the class to a String and it occurred to me that using reflection it might be possible to create a generic toString() method that could work on ALL classes. I.E. it would figure out the field names and values and send them out to a String.
Getting the field names is fairly simple, here is what a co-worker came up with:
public static List initFieldArray(String className) throws ClassNotFoundException {
Class c = Class.forName(className);
Field field[] = c.getFields();
List<String> classFields = new ArrayList(field.length);
for (int i = 0; i < field.length; i++) {
String cf = field[i].toString();
classFields.add(cf.substring(cf.lastIndexOf(".") + 1));
}
return classFields;
}
Using a factory I could reduce the performance overhead by storing the fields once, the first time the toString() is called. However finding the values could be a lot more expensive.
Due to the performance of reflection this may be more hypothetical then practical. But I am interested in the idea of reflection and how I can use it to improve my everyday programming.
Apache commons-lang ReflectionToStringBuilder does this for you.
import org.apache.commons.lang3.builder.ReflectionToStringBuilder
// your code goes here
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
Another option, if you are ok with JSON, is Google's GSON library.
public String toString() {
return new GsonBuilder().setPrettyPrinting().create().toJson(this);
}
It's going to do the reflection for you. This produces a nice, easy to read JSON file. Easy-to-read being relative, non tech folks might find the JSON intimidating.
You could make the GSONBuilder a member variable too, if you don't want to new it up every time.
If you have data that can't be printed (like a stream) or data you just don't want to print, you can just add #Expose tags to the attributes you want to print and then use the following line.
new GsonBuilder()
.setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.create()
.toJson(this);
W/reflection, as I hadn't been aware of the apache library:
(be aware that if you do this you'll probably need to deal with subobjects and make sure they print properly - in particular, arrays won't show you anything useful)
#Override
public String toString()
{
StringBuilder b = new StringBuilder("[");
for (Field f : getClass().getFields())
{
if (!isStaticField(f))
{
try
{
b.append(f.getName() + "=" + f.get(this) + " ");
} catch (IllegalAccessException e)
{
// pass, don't print
}
}
}
b.append(']');
return b.toString();
}
private boolean isStaticField(Field f)
{
return Modifier.isStatic(f.getModifiers());
}
If you're using Eclipse, you may also have a look at JUtils toString generator, which does it statically (generating the method in your source code).
You can use already implemented libraries, as ReflectionToStringBuilder from Apache commons-lang. As was mentioned.
Or write smt similar by yourself with reflection API.
Here is some example:
class UniversalAnalyzer {
private ArrayList<Object> visited = new ArrayList<Object>();
/**
* Converts an object to a string representation that lists all fields.
* #param obj an object
* #return a string with the object's class name and all field names and
* values
*/
public String toString(Object obj) {
if (obj == null) return "null";
if (visited.contains(obj)) return "...";
visited.add(obj);
Class cl = obj.getClass();
if (cl == String.class) return (String) obj;
if (cl.isArray()) {
String r = cl.getComponentType() + "[]{";
for (int i = 0; i < Array.getLength(obj); i++) {
if (i > 0) r += ",";
Object val = Array.get(obj, i);
if (cl.getComponentType().isPrimitive()) r += val;
else r += toString(val);
}
return r + "}";
}
String r = cl.getName();
// inspect the fields of this class and all superclasses
do {
r += "[";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
// get the names and values of all fields
for (Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())) {
if (!r.endsWith("[")) r += ",";
r += f.getName() + "=";
try {
Class t = f.getType();
Object val = f.get(obj);
if (t.isPrimitive()) r += val;
else r += toString(val);
} catch (Exception e) {
e.printStackTrace();
}
}
}
r += "]";
cl = cl.getSuperclass();
} while (cl != null);
return r;
}
}
Not reflection, but I had a look at generating the toString method (along with equals/hashCode) as a post-compilation step using bytecode manipulation. Results were mixed.
Here is the Netbeans equivalent to Olivier's answer; smart-codegen plugin for Netbeans.

Categories