Java analog for PHP's StdClass - java

I need something like a property bag to throw key value pairs into.
I want to create list of such objects, initialize them in bean and then use the list to render table in JSF template.
I know how to do it, but I want to avoid creating some special class for that case, like OrderLineItem and using List<OrderLineItem>.
I do not want to define new class.
In PHP I could use StdClass.
StdClass is a sparsely documented class in PHP which has no predefined members.
$object = new StdClass;
$object->foo = 'bar';
But, as far as I know, Primefaces <p:dataTable> list item must be an object with getter.
If I want to reference <h:outputText value="#{item.title}" />, my list object should have getTitle() method.
Is there any walkaround in my case or I really need to define special class to make life easier?
Thanks.

When you want a simple key/value table, then the HashMap might be what you are looking for.
Map<String, String> myMap = new HashMap<>();
myMap.put("foo", "bar");
System.out.println(myMap.get("foo")); // outputs "bar"
This example matches Strings to Strings, but you can use HashMaps to map any type to any other type. You can even create a Map<Object, Object> to create a weakly-typed map which maps anything to anything. But for most use-cases you would rather use a more specialized form.

What you need is a Map.
You can store key-value pairs in it pretty easy:
Map<KeyClass, ValueClass> myMap = new HashMap<KeyClass, ValueClass>();
Use the put method to put data in it. If you use simple String values it will be like this:
myMap.put("key", "value");

I don't know if I understood you well. But I think you mean SelectItem or JsfMap.

I would recommend to use an anonymous class:
return new HashMap<String, String>() {
{
this.put("key", "value");
}
};

Related

Is there a way to map a string to a method that returns a different type depending on the string?

I want to map a String to a method that builds a certain object, but not necessarily from the same class for every String. Looking around on here a nice solution was to have a Map<String, ObjectBuilder>, ObjectBuilder<T> being an interface with an abstract method T buildObject().
I then have multiple classes, let's say Object1Builder implements ObjectBuilder<Object1>, Object2Builder implements ObjectBuilder<Object2> and so on.
I can then construct my map like so :
stringToBuilder = new HashMap<String, ObjectBuilder>(){{
put(string1, Object1Builder);
put(string2, Object2Builder);
put(string3, Object3Builder);
}};
And I can then do Object1 myObject1 = stringToBuilder.get(string1).buildObject()
Problem is, I get an error
Raw use of parameterized class 'ObjectBuilder'
in IntelliJ when I instanciate and construct stringToBuilder and I understand it has something to do with not specifying the generic of the interface ObjectBuilder when constructing the map, but I don't see how I could circumvent this. Moreover, I'm not very satisfied with the fact that I'm storing these classes in a map, I wish I could access them through the map without having the whole instance in the map.
You've probably noticed I'm quite new to Java and all this but please be sure I'm trying my best. Thank you in advance :)
What you want will never be possible without explicit casts. The reason is that there is no direct relation between the map keys (strings) and values (ObjectBuilders).
If you can switch from strings to use the T values as map keys, this can be done with a little internal casting.
First, declare your map as Map<Class<?>, ObjectBuilder<?>>. Note the two wild-cards; the compiler cannot help us with enforcing that the keys and the values have the same generic type. That's what we need to do ourselves.
Next, initialize it as necessary. I dislike the anonymous class with initializer you use, so I'll use Map.of:
Map<Class<?>, ObjectBuilder<?>> classToBuilder = Map.of(
Object1.class, Object1Builder,
Object2.class, Object2Builder,
Object3.class, Object3Builder,
);
Finally, we need a method to get the builder:
#SuppressWarnings("unchecked")
private <T> getBuilder(Class<T> type) {
// Omitted: presence check
return (ObjectBuilder<T>) classToBuilder.get(type);
}
This can now be used as follows:
Object1 object1 = getBuilder(Object1.class).buildObject();

How can I store a set of URL parameters in Java?

Normally I would store URL parameters (GET request parameters) with a HashMap<String,String> but that doesnt account for URLs like test.php?request=id1&request=id2. Is there any data structure implemented in Java that can deal with this (and that I can query a parameter by name)? Alternatively, is there a single class somewhere that I can use (no libraries please)?
You can fake a multimap with something like this:
Map<String, List<String>> multimap = new HashMap<String, List<String>>();
See the 'MultiMap' section on this page for more information:
The Map Interface
If you are talking about using java to write servlet or something, as far as I know, the HttpServletRequest class comes with the parameter as a list, and for each parameter, the value is an array.
HttpServletRequest req=...
Enumeration<String> names=req.getParameterNames(); //
String para=names.getNextElement();//return "request"
String[] values=para.getParameterValues();// Should get["id1","id2"]
Now you certainly can use a list for it, like whiskeyspider suggested.
You can also make a wrapper on it before put into a hashMap,even just to serialize it. then we you need to use it, just unwrap it. But I would suggest use a list all the way, you can always just check the length to know if it is a single parameter or list.

How to serialize Map<String, List<Object>> with FlexJSON

I have a object which I want to serialize to JSON. This object is a map with list of a specific objects. This looks similar to it:
Map<String, List<Object>> map = new Map<String, List<Object>>();
I am using FlexJSON. I can work only with flexjson.JSONSerializer. There are my tries:
JSONSerializer jsonSerializer = new JSONSerializer();
// jsonSerializer.include("map");
// jsonSerializer.include("map.myList.object");
jsonSerializer.transform(new MapTransformer(), "map");
jsonSerializer.exclude("*.class");
As you can see I am trying now with Transformer classes but I haven't succeeded. The commented lines will work, as I suppose, if my List<Object> has own name for example myList. But it doesn't haven own name, because it is values of my map.
How can I serialize such object to JSON with FlexJSON?
Quoi is correct, and most likely the answer you want to use. However, just so you can learn more about how it works you could do this:
new JSONSerializer().include("values.values").serialize( myMap );
Maps and Lists are containers and have special expressions for the elements contained within them. When you want to talk about the path of the values of a container you use "values" expression in the path. Map's two special expressions "keys" and "values". Other Collections have "values".
Another option is to use wildcards like so:
new JSONSerializer().include("values.*").serialize( myMap );
You can see wildcards used in Quoi's answer as well to exclude the class property.
Try
String jsonString = new JSONSerializer().exclude("*.class").deepSerialize(map);
deepSerialize method performs a deep serialization of the target instance. It will include all collections, maps, and arrays by default so includes are ignored except if you want to include something being excluded by an annotation.

Set object fields from HashMap

Is there a library that can do the following?:
Given an Object and a HashMap, it enumerates the keys of the Hashmap and looks up the setters for these keys in the Object and sets the associated values. Something looking like that:
public Object setData(Object object, HashMap<String, Object> fields) {
for (Entry<String, Object> entry : fields.entrySet()) {
Method m = object.getClass().getMethod("set" + entry.getKey(), entry.getValue().getClass());
if (m != null) {
m.invoke(object, entry.getValue());
}
}
return object;
}
The task looks simple at the first look but there are some nuances that I hope someone has already taken care of. As you know, reinventing the wheel (the good wheel) is a bad approach.
Look at Apache Commons BeanUtils
org.apache.commons.beanutils.BeanUtils.populate(Object bean, Map properties)
Javadoc:
Populate the JavaBeans properties of the specified bean, based on the specified name/value pairs. This method uses Java reflection APIs to identify corresponding "property setter" method names, and deals with setter arguments of type String, boolean, int, long, float, and double.
Better use BeanUtils class:
public Object setData(Object object, HashMap<String, Object> fields) {
for(Entry<String, Object> entry : fields.entrySet()) {
BeanUtils.setProperty(object, entry.getKey(), entry.getValue());
}
return object;
}
I have a BeanAsMap class that I wrote a long time ago. The method asMap returns a Map that is a view on a Java bean (POJO). You can call putAll on that Map, passing it the Map that you want to copy data from.
Feel free to use my code mentioned above.
Example:
MyClass bean = ...;
Map<String, Object> inputData = ...;
Map<String, Object> view = BeanAsMap.asMap(bean);
view.putAll(inputData);
BeanUtils is fine.
But, as good practice, i would not write code that use reflection. Or as the last solution i have, if none other has been found.
This code cannot be tracked in IDE like Eclipse (no call hierarchy), making the developer think that the setters are never called. He can break your code and that will still compile.
Too high level of abstraction like this makes the code difficult to understand.
Code that is being obfuscated will be broken by the obfuscator itself when writting such things.
Best solution would be to rethink the use of reflection to set the object fields.
Check out http://commons.apache.org/beanutils/, in particular BeanUtils.populate():
http://commons.apache.org/beanutils/v1.8.3/apidocs/index.html

Is it possible to have a hashmap with 4 objects?

Can I have an hashMap with say ID as my key and info, name, quantity as my values?
ok, say I have a class (Products) already that sets my variables, getters and setters. In my Invoice class, which is where the hashMap would be. Would I put like:
private HashMap<String, Products> keys = new HashMap<String, Products>
I'm not quite sure how to access the HashMap though. Say I implement a class that allows me to add and remove invoices from the HashMap, I do not know what the values would be:
keys.put(??value of id??,??not sure what goes here??);
Sure. Make another class that contains your info, name and quantity and put that as the value of your HashMap.
No, but the best way is to wrap the information you want to keep in the map in a class:
public class Info {
private String info;
private String name;
private int quantity;
...
public Info(String info, String name, int quantity) {
...
}
}
Then do this to put something in the map:
Info info = new Info("info", "name", 2);
Map map = new HashMap<Integer, Info>();
map.put(22, info);
And do this to get something out:
Info info = map.get(22)
How about HashMap<Integer, ArrayList<String>> ?
UPDATE: Please try to avoid this, this is a better approach.
Not exactly.
A Map defines a strictly 1 to 1 relationship between keys and values. One key in the map has one value.
If you want to associate multiple values with one key you need to do one of the following:
Define a Values class to represent the values as a single object; e.g. as per #Starkey's and #Javed's answers. Then the map becomes a Map<String, Values> (assuming that the key type is String).
Define the map as a Map<String,List<Object>> or Map<String,Object[]> and represent the values as an untyped list / array
Define the map as a Map<String,Properties> or Map<String,Map<String,Object>> and represent the values as the Java equivalent of an associative array.
Of these, the first option is both the safest (smallest chance of runtime errors), the most efficient and the best style.
(Aside: an Apache commons MultiMap might be considered as another possibility, but the conceptual model and APIs don't really match this use-case.)
Sure. Depending on how flexible your datastructe is you can use a Hashmap a la:
HashMap<IdType, List<String>>, with IdType String or Integer, depending on the Keys you like to use.
HashMap<IdType, String[]>
HashMap<IdType, YourObjectType>, with YourObjectType beeing a Object you defined yourself, holding the values you like
YourObjectType can of course be anything you can define as an Object. Also another HashMap if you like.
One of the concerns while using a Map would be use of hardcoded keys. If the key is a string, and the key changes. Can consider using a constant instead of a hardcoded string.
Having a dedicated class has the benefit of compiler to check for name changes. However, as mentioned in the earlier comments.. It can become a concern...
In my opinion both are feasible. We need to weigh which option is better depending on the situation
Create an object that encapsulates the four together. Something like:
public class Foo {
private String s1;
private String s2;
private int v3;
private MyObject obj1
// constructors, getters, helper functions.
}
I think MultiMap from google library could serve the purpose
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html
Multimap<String, String> map = ArrayListMultimap.create();
String key = "uniqueKey";
map.put(key, "value1");
map.put(key, "value2");
map.put(key, "value3");
System.out.println(map);//{uniqueKey=[value1, value2, value3]}
Of course, you could for example declare it like this: HashMap<Integer, HashMap<String,Object>> You use the outer hashmap to link your id with your inner HashMap, and in the inner one, you create keys "info", "name", "quantity" and associate values with them.
Of course, you could also use an ArrayList as the outer collection (it could be a better match for your ID: ArrayList<HashMap<String,Object>> that way you have indexed (id based) access to each of your "info", "name", "quantity" hashmap "records"
You could have ID as key and a List or Set (Collection in general) of objects as value.

Categories

Resources