I have a Java Web Application with a HashMap class to store around 20 different web sites where the key is a specific code:
e.g code: AB website: http://www.somewebsiteforAB.com
I generate the code (HashMap key) via another Java Class which is surfaced in the JSP for user display.
I am trying to understand how I can pass this 'dynamic' variable from the JSP to the HashMap to return the associated value.
My Java class is:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Iterator;
import java.util.Set;
public class FaMap {
// Initialisers a static, immutable map containing relevant web sites
private static final Map<String, String> fMap;
static {
/* Declaring the HashMap*/
Map<String, String> aMap = new HashMap<String, String>();
/* Adding elements to HashMap*/
aMap.put("AB", "https://www.somewebsiteforAB.com/");
aMap.put("CD", "https://www.somewebsiteforCD.com/");
aMap.put("EF", "https://www.somewebsiteforEF.com/");
aMap.put("GH", "https://www.somewebsiteforGH.com/");
fMap = Collections.unmodifiableMap(aMap);
/* Display content using Iterator*/
Set<Entry<String, String>> set = fMap.entrySet();
Iterator<Entry<String, String>> iterator = set.iterator();
while (iterator.hasNext()) {
Entry<String, String> mentry = iterator.next();
}
}
}
The above class will print the keys and values for all or any specified key using System.out.println statements within the class. But how do I pass the map a dynamically generated key to extract the relevant value and pass this back to the JSP.
Do I need to write another method that accepts the key as an parameter and passes this to the map?
First of all, your dynamic var needs to be created. for example:
<c:set var="myVar" value="AB"/>
Once you have this, and have an instance of your map (let's call it fMap) you can simply call it like in Java. for example:
<c:set var="myWebsite" value="${fMap.get(myVar)}"/>
And you also need a pulbic Java method that will allow you access to the map. for example:
public Map<String, String> getMap() {
return fMap;
}
yes, you can just create a new method that will receive the key that is being displayed in your JSP.
Something like this:
public String getValueWithKey(String keyFromJSP) {
return fMap.get(keyFromJSP);
}
Related
I want to initialize a hashmap inside an nested interface. I have tried doing smtng like
interface constants{
.........
.........
interface anotherInterface{
........
........
Map<String, HttpMethod> API_METHOD = new HashMap<String,HttpMethod>();
API_METHOD.put(POST, HttpMethod.POST);
}
}
but this is givin error "Cannot resolve symbol 'put'".
can someone please tell me the reason for this and some other way to initialize the map.
Note: I don't want to initialize my map like and i am using java 8
new HashMap<String, HttpMethod>() {
{
put(POST, HttpMethod.POST);
}
};
Any 'field' in an interface immediately becomes a public static final one, therefore, making a mutable field is an incredibly bad idea - that's making global state, the thing just about every style guide out there lists as number one on the list of 'bad ideas'.
But, you're trying to 'initialize it', so I think your intent is that this map is itself 'constant' (it has a bunch of key/value mappings and can no longer be changed).
You have a few options.
You don't have many k/v pairs
Map<String, HttpMethod> API_METHOD = Map.of(
"POST", HttpMethod.POST,
"GET", HttpMethod.GET);
You have a lot of k/v pairs
Use the guava (a.k.a. google collections) library.
Then you can do:
Map<String, HttpMethod> API_METHOD = ImmutableMap.<String, HttpMethod>builder()
.put("POST", HttpMethod.POST)
.put("GET", HttpMethod.GET)
.build();
You have a lot and do not want to use guava
Now it gets a little mad, especially without java 11. You can write a static method in a class (which can be private if you want), and then call that static method from your interface:
public interface MyInterface {
Map<String, HttpMethod> httpMethods = MyInterfaceUtil.makeHttpMethodMap();
}
class MyInterfaceUtil {
static Map<String, HttpMethod> makeHttpMethodMap() {
Map<String, HttpMethod> map = new HashMap<>();
map.put("POST", HttpMethod.POST);
return Collections.unmodifiableMap(map);
}
}
Note:
That util class can be in the same file, but you should not make it public.
Collections.unmodifiableMap is very important.
I'm trying to create a mapping in which a UUID key points to both an object (e.g. some User class instance) and auxiliary information about that object (e.g. an int and a String). There are two obvious implementations of this:
import java.util.Map;
import java.util.HashMap;
import java.util.UUID;
...
Map<UUID, User> main = new HashMap<UUID, User>();
Map<UUID, Integer> aux1 = new HashMap<UUID, Integer>();
Map<UUID, String> aux2 = new HashMap<UUID, String>();
or
import java.util.Map;
import java.util.HashMap;
import java.util.UUID;
...
private static class UserInfo { // Nested class
public final User user;
public final int aux1;
public final String aux2;
public UserInfo(User user, int aux1, String aux2) {
this.user = user;
this.aux1 = aux1;
this.aux2 = aux2;
}
}
...
Map<UUID, UserInfo> main = new HashMap<UUID, UserInfo>();
Which is generally considered more performant, in terms of efficiency and memory usage? Or is there a more worthwhile third option?
For both memory and efficiency, I believe the second option is the better solution. The first solution is creating more Maps which use memory, and storing the same UUID which use memory.
It is also better for maintainability and readability, which unless performance to the millisecond is critical, is the more important of these. If you bundle the correlated information together, it is easier to determine where you got the information and what it is describing.
Also think about future development for the project, for example adding another descriptor for the user like aux3. For the first example you would need to add another hashmap, remember to add to the new hashmap, and remember to pull data from it as you are pulling from the others. This would create a lot of boilerplate for initial set up and access.
uuid = //some uuid
Map<UUID, Double> aux3 = new HashMap<UUID, Double>();
// some code
aux3.put(uuid, 1.0);
// some code ...
aux3.get();
But with composition method, you'd only need to remember to add the class property (with successors and mutators), and you are free to use these anywhere. Anytime you access from the user map, you only need I call to get(uuid) and you have access to all the associated data.
This is Subjective topic - evaluate below factors
Information Security (just because you mentioned user) - can you keep all the information together
depends on what you doing with these Maps and if there are likely to be issues because of later processing
otherwise, generally 2nd option (UserInfo class) is a good to idea.
I am working with Android Studio 1.4.1. I had just created a Hashmap and was following a tutorial (in Java) on how to populate and manipulate it.
However, I get a 'cannot resolve symbol put' error and the "put" command is in red.
The image I added shows the auto complete snapshot and although java.util.HashMap is imported, there isn't any "put" command that is available in autocomplete. The available commands also are showing in red. I tried to use them instead of the "put" command. I keep having this type of problem all along. How can I fix it?
import java.util.HashMap;
HashMap<String, String> pozisyon = new HashMap<String, String>();
pozisyon.put("SKale", "a8");
You cannot add elements in HashMap fields outside of methods. Things like this won’t work:
public class Class {
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("one", "two");
}
If you want to achieve that, put it in the constructors, like so:
public class Class {
HashMap<String, String> hashMap = new HashMap<String, String>();
public Class() {
hashMap.put("one", "two");
}
}
Another way you can do it is in a static block.
Assuming that you are wishing to put a value to a HashMap at the same time you initialize it. I will suggest you this "magic" Java syntax:
Try this:
public class ClassName {
HashMap<String, String> hashMap = new HashMap<String, String>(){
{
put("one", "two");
put("two", "three");
}
};
/*
Other code and constructor can go here.
....
....
*/
}
Indeed, from Java anywhere even on a non-function code section, you can immediately call the object instance function and properties by following the pattern shown above;-)
Try this:
public class Class {
HashMap arrayList1 = new HashMap<>();;
arrayList1.put("32", "Bangalore");
arrayList1.put("32", "India");
}
I'd like to create a key/value map structure using Google Guava where the keys cannot be modified but the values can. I also want the ability to use a predicate (or something similar) to iterate the Map and only retrieve those entries that have values.
For example, conceptually:
// start
Map data =
{Constants.KEY_NAME_1, Optional.absent()},
{Constants.KEY_NAME_2, Optional.absent()};
// succeeds
data.put(Constants.KEY_NAME_2, Optional.of("new_data"));
// finish
Map data =
{Constants.KEY_NAME_1, Optional.absent()},
{Constants.KEY_NAME_2, Optional("new_data")};
// fails
data.put(Constants.KEY_NAME_3, Optional.of("more_new_data"));
Any idea how to accomplish this?
-------- Solution --------
As per the comments below, I went with the ForwardingMap. The Implementation is straightforward
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableList;
import java.util.Map;
Map<String, String> labelMap = ImmutableMap.<String, String> builder()
.put("KEY_1", "data1")
.put("KEY_2", "data2")
.build();
MyCustomMap<String> map = new MyCustomMap(labelMap);
public class MyCustomMap<String> extends ForwardingMap<String, String> {
private final Map<String, String> delegate;
private final ImmutableMap<String, String> immutableMap;
public MyCustomMap(Map<String, String> labelMap) {
/*
Check for duplicate values in the map here. The construction of
the ImmutableMap above ensures that there are no duplicate
keys. Otherwise it will throw
"IllegalArgumentException: Multiple entries with same key".
*/
delegate = labelMap;
immutableMap = ImmutableMap.<String, String>builder().putAll(delegate).build();
}
#Override
protected Map<String, String> delegate() {
return immutableMap;
}
}
Guava cannot do anything for you if your keys are not immutable; this is something you have to ensure yourself (by making sure that the class of all keys is an immutable class).
Even an ImmutableMap is not immune to this kind of mishap:
// Modify the key
victim.keySet().iterator().next().alterMe();
If what you wish to do is customize the behavior upon insertion/retrieval then you can use a ForwardingMap to wrap another Map instance.
Beware however that this class leaves you a lot of freedom, including that of breaking the Map contract, which you should obviously refrain from!
I'd use an EnumMap that overwrites the put() method:
public enum Constants {
KEY_NAME_1, KEY_NAME_2, KEY_NAME_3;
#SuppressWarnings("serial")
public static <T> EnumMap<Constants, Optional<T>> asMap(
final Constants... validKeys) {
return new EnumMap<Constants, Optional<T>>(Constants.class) {
{
for (Constants c : validKeys) {
super.put(c, Optional.absent());
}
}
#Override
public Optional<T> put(Constants key, Optional<T> value) {
if (!this.containsKey(key)) {
throw new IllegalArgumentException("Invalid key");
}
return super.put(key, value);
}
};
}
public static <T> Map<Constants, Optional<T>> withValues(
EnumMap<Constants, Optional<T>> map) {
return Maps.filterValues(map, new Predicate<Optional<T>>() {
#Override
public boolean apply(Optional<T> input) {
return input.isPresent();
}
});
}
}
This is an enum with a static method that creates an anonymous EnumMap initialized with the provided keys. It uses the anonymous class' initializer block to map the provided keys to Optional.absent() and overrides the put
method to disallow putting keys not provided as arguments.
It also has a helper method that returns a view of the map containing the entries that have a value different than Optional.absent().
Sample usage:
// Create map with KEY_NAME_1 and KEY_NAME_2 only
EnumMap<Constants, Optional<String>> map =
Constants.asMap(Constants.KEY_NAME_1, Constants.KEY_NAME_2);
System.out.println(map); // {KEY_NAME_1=Optional.absent(), KEY_NAME_2=Optional.absent()}
map.put(Constants.KEY_NAME_2, Optional.of("two"));
System.out.println(map); // {KEY_NAME_1=Optional.absent(), KEY_NAME_2=Optional.of(two)}
Map<Constants, Optional<String>> withValues = Constants.withValues(map);
System.out.println(withValues); // {KEY_NAME_2=Optional.of(two)}
map.put(Constants.KEY_NAME_3, Optional.of("three")); // throws IllegalArgumentException
// TODO Override remove() in returned map so that instead of removing the entry it sets an Optional.absent(). Same with other methods that might affect the map.
I don't think Guava can do that for you. Guava defines ImmutableMap which means neither the keys nor the values can be modified. What you are describing is more like a static array than a map, where the array positions map to fixed keys. You might be better off writing your own Map implementation. You could store an ImmutableMap<Key,Integer> for the keys, where the values are the positions in an array of the actual map values, say Value[], initialized with the size of the set of keys. Then you can implement your custom put that throws an exception if the provided key is not in the ImmutableMap.
Or you can just define a wrapper for some Map implementation that implements put.
I am new to OGNL. I am trying to write OGNL expressions in core java to retrieve properties/call methods.
Here is my test class.It has a List of keys and a Map which uses these keys to store values.
Please see below
package ognl.test;
import java.util.List;
import java.util.Map;
public class OGNLTestProg {
List<String> keys = null;
Map<String, Object> data = null;
public OGNLTestProg(List<String> keys, Map<String, Object> data){
this.keys = keys;
this.data = data;
}
public List<String> getKeys(){
return keys;
}
public Object getData(String key){
return data.get(key);
}
}
Here is the test program that instantiates an object of the above class and uses OGNL to call some methods.
package ognl.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ognl.Ognl;
public class Test {
public static void main(String[] args) throws Exception {
String str1 = "1";
String str2 = "2";
List<String> keys = new ArrayList<String>();
keys.add(str1);
keys.add(str2);
User u1 = new User();
u1.setFirstName("x");
u1.setLastName("y");
User u2 = new User();
u2.setFirstName("x1");
u2.setLastName("y1");
Map<String, Object> data = new HashMap<String, Object>();
data.put(str1, u1);
data.put(str2, u2);
OGNLTestProg o = new OGNLTestProg(keys, data);
/**
#{
#outerObj = #this,
'users': getKeys().
{
#{
#user = outerObj.getData(#this),
#{
'firstName': user.getFirstName(),
'lastName':user.getLastName()
}
}
}
}
*/
Object expression1 = Ognl.parseExpression("#{"+
"#outerObj = #this,"+
"'users': getKeys()."+
"{"+
"#{"+
"#user = outerObj.getData(#this),"+
"#{ 'firstName': user.getFirstName(),"+
"'lastName':user.getLastName()"+
"}"+
"}" +
"}"+
"}");
Map<String,Object> map = (Map<String,Object>)Ognl.getValue(expression1, o);
}
}
User is a custom class that has firstName and lastName as properties.
What I am trying to achieve using the OGNL expr is to iterate the list, retrieve each key and then pass that key to the map to retrieve the value (User object) and then call some property on that object.
While I am able to iterate the list using
'users': getKeys().{
//I need to access the getData() method of the root object here passing the current #this object
}
My OGNL expression throws the following error
Exception in thread "main" ognl.NoSuchPropertyException: java.lang.String.outerObj
Please help. I found tons of stuff on google on using OGNL with struts2 tags, but there's nothing much on its usage to access object properties like above.
Regards,
Suv
If I were going to implement the functionality it looks like you want then I'd probably use a google guava Table object to create the multiple indexed user object which you can then retrieve with a single simple map.get(key) call.
What you have in your example is even matched exactly in the guava Table wiki tutorial on the API. You're making it more complicated than it has to be otherwise. ;)