java string subsitutions using object - java

Output of the below code is :
This is Raja from ${Address.Street} i did my ${Education.degree} from ${Education.university}
but what I need is
This is Raja from Namakkal i did my B.E from Anna University
is it possible to achieve by using Freemarker, OGNL or by using spring.
public class Test
{
public static void main(String arg[]) throws TemplateModelException
{
Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> address = new HashMap<String, Object>();
address.put("Street", "Namakkal");
Qualification qualification = new Test.Qualification();
map.put("Name", "Raja");
map.put("Address", address);
map.put("Education", qualification);
StrSubstitutor strsub = new StrSubstitutor(map);
String str = "This is ${Name} from ${Address.Street} i did my ${Education.degree} from ${Education.university}";
System.out.println(strsub.replace(str));
}
public static class Qualification
{
public String getDegree()
{
return "B.E";
}
public String getUniversity()
{
return "Anna University";
}
}
}
please explain the simplest and effective way to achieve this.

If you want to use StrSubstitutor itself, you could try using a custom variable resolver by extending the StrLookUp class.
Example:
StrSubstitutor strsub = new StrSubstitutor(new CustomLookUp(map));
...
...
private static class CustomLookUp extends StrLookup<Object> {
Map<String, Object> map = new HashMap<String, Object>();
public CustomLookUp(Map<String, Object> map) {
this.map = map;
}
#Override
public String lookup(String key) {
// ...
// Logic for resolving your variables.
// ...
}
}

You could do it with freemarker, using the StringTemplateLoader class. This class allows you to create templates from Strings, instead of reading them from files.

Without freemarker you can use the following:
String str="This is "+(String)map.get("Name")+" from "+((Map)map.get("Address")).get("Street")+". I did my "+((Qualification)map.get("Education")).getDegree()+" from "+((Qualification)map.get("Education")).getUniversity()+".";

#Anoop example implementation with spring reflection
#Override
public String lookup(String key) {
String[] keys = key.split("\\.");
Object obj = map.get(keys[0]);
for (int i = 1; i < keys.length; i++) {
Class<?> clazz = obj.getClass();
Field field = null;
try {
field = org.springframework.util.ReflectionUtils.findField(clazz, (keys[i]));
org.springframework.util.ReflectionUtils.makeAccessible(field);
obj = field.get(obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return (String) obj;
}

Related

In Java, is there any way to alias an object field so that it has two names?

I'm getting back into Java programming, and I have a situation where I'd like to do something like this:
public class FieldAliasTest {
static public class Something {
#Alias("somethingId")
public Long id;
#Alias("id")
public Long somethingId;
}
static public void main(String[]args) {
Something mySomething = new Something();
mySomething.id = 1L;
assert(mySomething.somethingId == 1L);
mySomething.somethingId = 2L;
assert(mySomething.id == 2L);
}
}
Is there anything in the Java standard, Spring Boot, and/or Lombok libraries that would make that possible?
Is it possible at all?
I'm trying to avoid adding any functions like setSomethingId() and setId().
In short, no. Java does not support this.
You can build something like this, noting that you define aliases per instance, not on the class itself. Modify as needed:
public class AliasThingy {
private final Map<String, Object> storage = new HashMap<>();
private final Map<String, String> aliases = new HashMap<>();
public AliasThingy (Map<String, List<String>> aliases) {
aliases.forEach((key, value) -> value.forEach(alias -> this.aliases.put(alias, key)));
}
public void set(String key, Object value) {
storage.put(aliases.getOrDefault(key, key), value);
}
public <T> T get(String key) {
return (T)storage.get(aliases.getOrDefault(key, key));
}
public static void main(String[] args) {
var something = new AliasThingy(Map.of(
"id", List.of("somethingId")
));
something.set("id", 1L);
assert((long)something.get("somethingId") == 1L);
something.set("somethingId", 2L);
assert((long)something.get("id") == 2L);
}
}
You could also use it as a base class, which lets you define the aliases in the class definition, plus an opportunity to avoid raw strings:
public class Something extends AliasThingy {
public interface KEYS {
String ID = "id";
String SOMETHING_ID = "somethingId";
String NAME = "name";
String DESCRIPTION = "description";
String TITLE = "title";
}
public Something() {
super(Map.of(
KEYS.ID, List.of(KEYS.SOMETHING_ID),
KEYS.NAME, List.of(KEYS.DESCRIPTION, KEYS.TITLE)
));
}
public static void main(String[] args) {
Something something = new Something();
something.set(KEYS.ID, 1L);
assert((long)something.get(KEYS.SOMETHING_ID) == 1L);
something.set(KEYS.SOMETHING_ID, 2L);
assert((long)something.get(KEYS.ID) == 2L);
something.set(KEYS.TITLE, "Dr. Strangelove");
assert(something.get(KEYS.NAME).equals("Dr. Strangelove"));
assert(something.get(KEYS.DESCRIPTION).equals("Dr. Strangelove"));
}
}

Filter pojo properties by some pattern

I've some server response (a long one) which I've converted to POJO (by using moshi library).
Eventually I have list of "Items" , each "Item" looks like follow :
public class Item
{
private String aa;
private String b;
private String abc;
private String ad;
private String dd;
private String qw;
private String arew;
private String tt;
private String asd;
private String aut;
private String id;
...
}
What I actually need, is to pull all properties which start with "a" , and then I need to use their values for further req ...
Any way to achieve it without Reflection ? (usage of streams maybe ?)
Thanks
With guava-functions tranformation you might transform your items with somethng following:
public static void main(String[] args) {
List<Item> items //
Function<Item, Map<String, Object>> transformer = new Function<Item, Map<String, Object>>() {
#Override
public Map<String, Object> apply(Item input) {
Map<String, Object> result = new HashMap<String, Object>();
for (Field f : input.getClass().getDeclaredFields()) {
if(! f.getName().startsWith("a")) {
continue;
}
Object value = null;
try {
value = f.get(input);
} catch (IllegalAccessException e) {
throw new RuntimeException("failed to cast" + e)
}
result.put(f.getName(), value);
}
return result
};
Collection<Map<String, Object> result
= Collections2.transform(items, transformer);
}
Sounds like you may want to perform your filtering on a regular Java map structure.
// Dependencies.
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Map<String, String>> itemAdapter =
moshi.adapter(Types.newParameterizedType(Map.class, String.class, String.class));
String json = "{\"aa\":\"value1\",\"b\":\"value2\",\"abc\":\"value3\"}";
// Usage.
Map<String, String> value = itemAdapter.fromJson(json);
Map<String, String> filtered = value.entrySet().stream().filter(
stringStringEntry -> stringStringEntry.getKey().charAt(0) == 'a')
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
You could wrap up the filtering logic in a custom JsonAdapter, but validation and business logic tends to be nice to leave to the application usage layer.

Retrieve used groovy variable after evaluate

I'm using groovy like an evaluator/compilator from my java application.
For example, I set a variable via the groovy binding (HS1 = 1, HS2 = 5)
binding.setVariable("HS1", 1);
binding.setVariable("HS2", 5);
and I launch an operation and catch the result via the groovy evaluate method( HS3 = HS1 + HS2)
value = (Number) shell.evaluate("HS3=HS1+HS2");
For my application, I would like to retrieve the used variable during my last operation (HS1 and HS2 in this case). I'm trying to use the binding.getVariables() method but it returns all the groovy session variable and not the last used variable.
Have you an idea to do that?
ps: Not easy to explain that with my french english level
You need retrieve the value with binding
#org.junit.Test
public void test(){
Binding binding = new Binding();
binding.setVariable("HS1", 1);
binding.setVariable("HS2", 5);
//binding.setVariable("HS3", new Integer());
GroovyShell gs = new GroovyShell(binding);
binding.beginCut(new LinkedHashMap<String, Object>());
Object o = gs.evaluate("HS3=HS1+HS2");
logger.info("GroovyTest.test: end cut");
logger.info("GroovyTest.test: "+o);
Map<String, Object> properties = binding.endCut();
logger.info("GroovyTest.test: ------");
for (Object v : properties.keySet()){
logger.info("GroovyTest.test: "+v);
}
Number sResult = (Number)binding.getVariable( "HS3" ) ;
logger.info(sResult);
}
public class MyBinding extends Binding {
private static org.apache.log4j.Logger logger = org.apache.log4j.Logger
.getLogger(MyBinding.class);
#Override
public Object getVariable(String name) {
logger.info("MyBinding.getVariable: request " + name);
Object value = super.getVariable(name);
//filter the requested variable
if (properties != null) {
properties.put(name, value);
}
return value;
}
Map<String, Object> properties = null;
public void beginCut(Map<String, Object> properties) {
this.properties = properties;
}
public Map<String, Object> endCut() {
Map<String, Object> properties = this.properties;
this.properties = null;
return properties;
}
}

How to check if variable name contains string and then output string variable content

So I have these 4 variables
private final String PROG_DEPT = "PROGRAMMING/ENGINEERING";
private final String DES_DEPT = "DESIGN/WRITING";
private final String ART_DEPT = "VISUAL ARTS";
private final String SOUND_DEPT = "AUDIO";
What I want to be able to do is to get a string and compare it to the variable and then out put what the variable contains if it equals it.
For example if my string equals "ART_DEPT" then it check if there is a variable called ART_DEPT and then output "VISUAL ARTS"
I was thinking of putting it in a 2D String array or a list but I'm not really sure as to how to do what I want to do
The data type you're looking for is Map<String, String>.
Map<String, String> departmentNames = new HashMap<String, String>();
departmentNames.put("PROG_DEPT", "PROGRAMMING/ENGINEERING");
departmentNames.put("DES_DEPT", "DESIGN/WRITING");
//...etc...
//...
String dept = "PROG_DEPT";
String deptName = departmentNames.get(dept);
System.out.println(deptName); //outputs "PROGRAMMING/ENGINEERING"
A Map binds a unique key to a value. In this case both have the type String. You add bindings using put(key, value) and get the binding for a key using get(key).
I would go with an enum:
package com.stackoverflow.so18327373;
public class App {
public static void main(final String[] args) {
final String in = "DES_DEPT";
try {
final Departement departement = Departement.valueOf(in);
System.out.println(departement.getLabel());
} catch (final IllegalArgumentException ex) {
// in was not a known departement
System.err.println("Bad value: " + in);
}
}
public static enum Departement {
PROG_DEPT("PROGRAMMING/ENGINEERING"),
DES_DEPT("DESIGN/WRITING"),
ART_DEPT("VISUAL ARTS"),
SOUND_DEPT("AUDIO");
private final String label;
private Departement(final String label) {
this.label = label;
}
public String getLabel() {
return this.label;
}
}
}
then use valueOf()
You probably want to use some kind of Map, such as a HashMap<String,String>. I suggest you read the Javadocs for the Map interface and the HashMap class.
What you need to use is a Map.
private final Map<String,String> myMap= new HashMap<String,String>() ;
{
myMap.put("PROG_DEPT","PROGRAMMING/ENGINEERING");
myMap.put("DES_DEPT","DESIGN/WRITING");
myMap.put("ART_DEPT","VISUAL ARTS");
myMap.put("SOUND_DEPT","AUDIO");
}
Then use it in the following way:
String input= "ART_DEPT" ;
System.out.println( myMap.get(input) );
Try this
List<String> list=new ArrayList<>();
list.add("private final String PROG_DEPT = \"PROGRAMMING/ENGINEERING\";");
list.add("private final String DES_DEPT = \"DESIGN/WRITING\";");
list.add("private final String ART_DEPT = \"VISUAL ARTS\";");
list.add("private final String SOUND_DEPT = \"AUDIO\";");
String search="ART_DEPT";
for (String i:list){
if(i.contains(search)){
System.out.println(i.split("=")[1].replaceAll(";",""));
}
}
Live Demo here. You can do this using Map but to do that you have to create a map from these Strings.
Sounds like you are looking for reflection (or if you want to use a different data type instead of looking up a variable in a class then a Map<String, String>). Looks like the Map approach is well covered, so only because this is interesting to me, here is the reflection approach (not that this is not the best way to solve this problem, but since you asked for checking if a variable exists and then getting it's value)
import java.lang.reflect.Field;
public class SOQuestion {
private final String PROG_DEPT = "PROGRAMMING/ENGINEERING";
private final String DES_DEPT = "DESIGN/WRITING";
private final String ART_DEPT = "VISUAL ARTS";
private final String SOUND_DEPT = "AUDIO";
public static void main(String ... args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
System.out.println(reflectValue("ART_DEPT", SOQuestion.class));
System.out.println(reflectValue("COMP_DEPT", SOQuestion.class));
}
public static String reflectValue(String varible, Class thing) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
Field[] fs = thing.getDeclaredFields();
for(int i = 0; i < fs.length; i++) {
if(fs[i].getName().equals(varible)) {
fs[i].setAccessible(true);
return (String) fs[i].get(thing.newInstance());
}
}
return null;
}
}
The first request to print "ATR_DEPT" will print VISUAL ARTS and the second request to the nonexistent "COMP_DEPT" will return null;
private String getStaticFieldValue(String fieldName){
String value = null;
try {
Field field = getClass().getDeclaredField(fieldName);
if (Modifier.isStatic(field.getModifiers())){
value = field.get(null).toString();
}
}
catch (Exception e) {
return null;
}
return value;
}
you have few options as mentioned above :
using a Map , the disadvantage of using a map for this case is that you will have to maintain it, it means that every time you will need to add/remove/edit one of your final static fields, you will have to edit the map as well.
using reflection as mentioned in this post, which is my favorite solution (the above code snippet)
Use the concept of Map
import java.util.HashMap;
import java.util.Map;
public class MajorMap {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String, String> deptMap = new HashMap<String, String>();
deptMap.put("PROG_DEPT", "PROGRAMMING/ENGINEERING");
deptMap.put("DES_DEPT","DESIGN/WRITING");
deptMap.put("ART_DEPT","VISUAL ARTS");
deptMap.put("SOUND_DEPT","AUDIO");
System.out.println("ART_DEPT----->>"+deptMap.get("ART_DEPT"));
}
}

Recursive BeanUtils.describe()

Is there a version of BeanUtils.describe(customer) that recursively calls the describe() method on the complex attributes of 'customer'.
class Customer {
String id;
Address address;
}
Here, I would like the describe method to retrieve the contents of the address attribute as well.
Currently, all I have can see the name of the class as follows:
{id=123, address=com.test.entities.Address#2a340e}
Funny, I would like the describe method to retrieve the contents of nested attributes as well, I don't understand why it doesn't. I went ahead and rolled my own, though. Here it is, you can just call:
Map<String,String> beanMap = BeanUtils.recursiveDescribe(customer);
A couple of caveats.
I'm wasn't sure how commons BeanUtils formatted attributes in collections, so i went with "attribute[index]".
I'm wasn't sure how it formatted attributes in maps, so i went with "attribute[key]".
For name collisions the precedence is this: First properties are loaded from the fields of super classes, then the class, then from the getter methods.
I haven't analyzed the performance of this method. If you have objects with large collections of objects that also contain collections, you might have some issues.
This is alpha code, not garunteed to be bug free.
I am assuming that you have the latest version of commons beanutils
Also, fyi, this is roughly taken from a project I've been working on called, affectionately, java in jails so you could just download it and then run:
Map<String, String[]> beanMap = new SimpleMapper().toMap(customer);
Though, you'll notice that it returns a String[], instead of a String, which may not work for your needs. Anyway, the below code should work, so have at it!
public class BeanUtils {
public static Map<String, String> recursiveDescribe(Object object) {
Set cache = new HashSet();
return recursiveDescribe(object, null, cache);
}
private static Map<String, String> recursiveDescribe(Object object, String prefix, Set cache) {
if (object == null || cache.contains(object)) return Collections.EMPTY_MAP;
cache.add(object);
prefix = (prefix != null) ? prefix + "." : "";
Map<String, String> beanMap = new TreeMap<String, String>();
Map<String, Object> properties = getProperties(object);
for (String property : properties.keySet()) {
Object value = properties.get(property);
try {
if (value == null) {
//ignore nulls
} else if (Collection.class.isAssignableFrom(value.getClass())) {
beanMap.putAll(convertAll((Collection) value, prefix + property, cache));
} else if (value.getClass().isArray()) {
beanMap.putAll(convertAll(Arrays.asList((Object[]) value), prefix + property, cache));
} else if (Map.class.isAssignableFrom(value.getClass())) {
beanMap.putAll(convertMap((Map) value, prefix + property, cache));
} else {
beanMap.putAll(convertObject(value, prefix + property, cache));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return beanMap;
}
private static Map<String, Object> getProperties(Object object) {
Map<String, Object> propertyMap = getFields(object);
//getters take precedence in case of any name collisions
propertyMap.putAll(getGetterMethods(object));
return propertyMap;
}
private static Map<String, Object> getGetterMethods(Object object) {
Map<String, Object> result = new HashMap<String, Object>();
BeanInfo info;
try {
info = Introspector.getBeanInfo(object.getClass());
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
Method reader = pd.getReadMethod();
if (reader != null) {
String name = pd.getName();
if (!"class".equals(name)) {
try {
Object value = reader.invoke(object);
result.put(name, value);
} catch (Exception e) {
//you can choose to do something here
}
}
}
}
} catch (IntrospectionException e) {
//you can choose to do something here
} finally {
return result;
}
}
private static Map<String, Object> getFields(Object object) {
return getFields(object, object.getClass());
}
private static Map<String, Object> getFields(Object object, Class<?> classType) {
Map<String, Object> result = new HashMap<String, Object>();
Class superClass = classType.getSuperclass();
if (superClass != null) result.putAll(getFields(object, superClass));
//get public fields only
Field[] fields = classType.getFields();
for (Field field : fields) {
try {
result.put(field.getName(), field.get(object));
} catch (IllegalAccessException e) {
//you can choose to do something here
}
}
return result;
}
private static Map<String, String> convertAll(Collection<Object> values, String key, Set cache) {
Map<String, String> valuesMap = new HashMap<String, String>();
Object[] valArray = values.toArray();
for (int i = 0; i < valArray.length; i++) {
Object value = valArray[i];
if (value != null) valuesMap.putAll(convertObject(value, key + "[" + i + "]", cache));
}
return valuesMap;
}
private static Map<String, String> convertMap(Map<Object, Object> values, String key, Set cache) {
Map<String, String> valuesMap = new HashMap<String, String>();
for (Object thisKey : values.keySet()) {
Object value = values.get(thisKey);
if (value != null) valuesMap.putAll(convertObject(value, key + "[" + thisKey + "]", cache));
}
return valuesMap;
}
private static ConvertUtilsBean converter = BeanUtilsBean.getInstance().getConvertUtils();
private static Map<String, String> convertObject(Object value, String key, Set cache) {
//if this type has a registered converted, then get the string and return
if (converter.lookup(value.getClass()) != null) {
String stringValue = converter.convert(value);
Map<String, String> valueMap = new HashMap<String, String>();
valueMap.put(key, stringValue);
return valueMap;
} else {
//otherwise, treat it as a nested bean that needs to be described itself
return recursiveDescribe(value, key, cache);
}
}
}
The challenge (or show stopper) is problem that we have to deal with an object graph instead of a simple tree. A graph may contain cycles and that requires to develop some custom rules or requirements for the stop criteria inside the recursive algorithm.
Have a look at a dead simple bean (a tree structure, getters are assumed but not shown):
public class Node {
private Node parent;
private Node left;
private Node right;
}
and initialize it like this:
root
/ \
A B
Now call a describe on root. A non-recursive call would result in
{parent=null, left=A, right=B}
A recursive call instead would do a
1: describe(root) =>
2: {parent=describe(null), left=describe(A), right=describe(B)} =>
3: {parent=null,
{A.parent=describe(root), A.left=describe(null), A.right= describe(null)}
{B.parent=describe(root), B.left=describe(null), B.right= describe(null)}}
and run into a StackOverflowError because describe is called with objects root, A and B over and over again.
One solution for a custom implementation could be to remember all objects that have been described so far (record those instances in a set, stop if set.contains(bean) return true) and store some kind of link in your result object.
You can simple use from the same commom-beanutils:
Map<String, Object> result = PropertyUtils.describe(obj);
Return the entire set of properties for which the specified bean provides a read method.

Categories