Support Map<String, String> & Map<String, MyString>

A

albert kao

The following programs work but I like to combine MyComboBox &
MyComboBox2 into one class so that both Map<String, String> &
Map<String, MyString> data types are supported in the single combined
class.
How to do that?

public class MyComboBox extends LangComboBox implements
PropertyChangeListener {
protected EventListenerList listenerList = new EventListenerList();
private Set keySet = Collections.EMPTY_SET;

public MyComboBox(Map items) {
super(items.values().toArray());
keySet = items.keySet();
}
//...
}

public class MyComboBox2 extends LangComboBox implements
PropertyChangeListener {
protected EventListenerList listenerList = new EventListenerList();
private Set keySet = Collections.EMPTY_SET;

public MyComboBox2(Map<String, MyString> items) {
super(MyStringUtil.sort(items).values().toArray());
Map<String, MyString> itemsSorted = MyStringUtil.sort(items);
keySet = itemsSorted.keySet();
}
//...
}

public class MyStringUtil
public static Map<String, MyString> sort(
Map<String, MyString> map) {
//...
}
}

// Calling program
Map<String, String> map1 = getdata("data1");
MyComboBox box1 = new MyComboBox(map1); // this is ok
Map<String, MyString> map2 = getdata2("data2");
MyComboBox2 box2 = new MyComboBox2(map2); // this is ok



MyString is a third party class which I don't have the source code. It
has the toString() method.
It does not implement CharSequence.
MyComboBox cannot have two constructors because of type erasure of the
generic type java.util.Map, the two methods are considered the same:
public MyComboBox(Map<String, String> items) {
//...
}
public MyComboBox(Map<String, MyString> items) {
//...
}
// These are the compile errors:
Duplicate method MyComboBox(Map<String,String>) in type MyComboBox
client/swing/components MyComboBox.java
Duplicate method MyComboBox(Map<String,MyString>) in type MyComboBox
client/swing/components MyComboBox.java



The following code gets ClassCastException.
Map<String, String> map1 = getdata("data1");
// this will cause casting exception - Exception in thread "AWT-
EventQueue-0"
// java.lang.ClassCastException: java.lang.String cannot be cast to
mycom.lang.MyString
// at myproj.client.swing.util.MyStringUtil
$MapComparable.compare(MyStringUtil.java:25)
MyComboBox2 box1 = new MyComboBox2(map1);
 
L

Lew

albert said:
The following programs work but I like to combine MyComboBox &
MyComboBox2 into one class so that both Map<String, String> &
Map<String, MyString> data types are supported in the single combined
class.
How to do that?

Have 'MyString' implement 'CharSequence' and use a 'Map said:
public class MyComboBox extends LangComboBox implements
PropertyChangeListener {
protected EventListenerList listenerList = new EventListenerList();
private Set keySet = Collections.EMPTY_SET;

DO NOT USE RAW TYPES!
 
D

Daniel Pitts

Have 'MyString' implement 'CharSequence' and use a 'Map<String,CharSequence>'?
Or, if you don't really care about the value type, use Map<String, ?> as
the parameter type.

public class MyComboBox {
public MyComboBox(Map<String, ?> data) {...};
}

If you *do* care about the type, then make your ComboBox generic:

public class MyComboBox<V> {
DO NOT USE RAW TYPES!
Seconded.
 
A

albert kao

Or, if you don't really care about the value type, use Map<String, ?> as
the parameter type.

public class MyComboBox {
    public MyComboBox(Map<String, ?> data) {...};

}

If you *do* care about the type, then make your ComboBox generic:

public class MyComboBox<V> {
    public MyComboBox(Map<String, V> data) {...};

}



Seconded.

Inside the MyComboBox constructor, is there a way to figure out
whether the type of value of the Map is String or MyString?
 
D

Daniel Pitts

Inside the MyComboBox constructor, is there a way to figure out
whether the type of value of the Map is String or MyString?

Not really, due to type erasure. It might be helpful if you explain
*why* you need the two constructors. What do they do differently?

Perhaps you're trying to fit a square peg into a round hole. What does
MyString provide that String doesn't?
 
A

albert kao

Not really, due to type erasure.  It might be helpful if you explain
*why* you need the two constructors. What do they do differently?

Perhaps you're trying to fit a square peg into a round hole.  What does
MyString provide that String doesn't?

MyString supports English and French language / Locale.
It will be sorted by the Collator class.
Pseudo code is:
If (input type is MyString)
sort by the Collator class
else
sort by the Collections.sort or TreeMap.
 
A

albert kao

Not really, due to type erasure.  It might be helpful if you explain
*why* you need the two constructors. What do they do differently?
//Two slightly different types of data stored in java.util.Map.
Map<String, String> map1 = getdata("data1");
Map<String, MyString> map2 = getdata2("data2");

// Use two slightly different ComboBoxes to sort & display the two
types of data
MyComboBox box1 = new MyComboBox(map1);
MyComboBox2 box2 = new MyComboBox2(map2);

// Is there a way to use the same type of ComboBox to sort & display
the two types of data?
MyComboBoxNew box1 = new MyComboBoxNew(map1);
MyComboBoxNew box2 = new MyComboBoxNew(map2);
 
L

Lew

albert said:
'MyString' do NOT implement 'CharSequence', so it cannot use a
'Map<String,CharSequence>'

I was suggesting that you change MyString. Obviously it doesn't implement that interface now, which is why I suggesting making that change. If it had already implemented 'CharSequence' you wouldn't be here asking your question. True?

No worries, you can use the 'Map<String, ?>' trick suggested upthread. Then you can use the same 'ComboBox' for either kind, assuming a suitable 'toString()' method for 'MyString'.

DO NOT USE RAW TYPES!

Code to check the type at run time is usually, and in your case definitely a sign of incomplete design. Make your structures type safe at the compiler-enforced level.

And have I mentioned that you should not use raw types?

DO NOT USE RAW TYPES!
 
A

albert kao

I was suggesting that you change MyString.  Obviously it doesn't implement that interface now, which is why I suggesting making that change.  Ifit had already implemented 'CharSequence' you wouldn't be here asking yourquestion.  True?

No worries, you can use the 'Map<String, ?>' trick suggested upthread.  Then you can use the same 'ComboBox' for either kind, assuming a suitable 'toString()' method for 'MyString'.  

DO NOT USE RAW TYPES!

Code to check the type at run time is usually, and in your case definitely a sign of incomplete design.  Make your structures type safe at the compiler-enforced level.

And have I mentioned that you should not use raw types?

DO NOT USE RAW TYPES!

These are my test programs:
import java.util.HashMap;
import java.util.Map;

public class MyComboBox {
public MyComboBox(Map<String, ?> data) {
HashMap<String, String> sorted_map = (HashMap<String, String>)
MapUtil.sortByValue(data);
for (String key : sorted_map.keySet()) {
System.out.println("key/value: " + key +
"/"+sorted_map.get(key).toString());
}
}

public static void main(String[] args)
{
Map<String, String> map1 = new HashMap<String, String>();
map1.put("key1", "value1");
map1.put("key3", "value3");
map1.put("key2", "value2");
MyComboBox box1 = new MyComboBox(map1);

Map<String, MyString> map2 = new HashMap<String, MyString>();
MyString s1 = new MyString();
s1.setEnglish("test1");
MyString s2 = new MyString();
s1.setEnglish("test2");
MyString s3 = new MyString();
s1.setEnglish("test3");
map2.put("key1", s1);
map2.put("key3", s3);
map2.put("key2", s2);
MyComboBox box2 = new MyComboBox(map2);
}
} // MyComboBox

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class MapUtil {
public static <K, V> Map<K, V> sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(
map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return (o1.getValue()).equals(o2.getValue()) ? 1 : 0;
}
});

Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}

public static <K, V extends Comparable<? super V>> Map<K, V>
sortByValue2(
Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(
map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return (o1.getValue()).compareTo(o2.getValue());
}
});

Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
} // MapUtil

// test class only because I don't have the actual source code
public class MyString {
String ls;

public MyString() {
//
}

public void setEnglish(String s) {
ls = s;
}

public void setFrench(String s) {
ls = s;
}
}

Running the test program has the following ClassCastException.
How to fix the problem?
key/value: key3/value3
key/value: key2/value2
key/value: key1/value1
Exception in thread "main" java.lang.ClassCastException: MyString
cannot be cast to java.lang.String
at MyComboBox.<init>(MyComboBox.java:10)
at MyComboBox.main(MyComboBox.java:32)
 
R

Roedy Green

Map<String, String> &
Map<String, MyString> data types are supported in the single combined
class.
Remember that at run time generic are erased. You would have a class
supporting two identical Map interfaces. I would expect it to spit at
you.

What you can do is have delegate objects that each support a map
interface.

see http://mindprod.com/jgloss/delegate.html
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
R

Roedy Green

I look at http://mindprod.com/jgloss/delegate.html but still don't
know how to apply it to my situation.
Would you mind posting some source codes?

What you do is in your class have something like this:

HashtMap<String,Thing> map1;
HashMap<String,String> map2;

public Map getMap1() { return map1; }
public Map getMay2() { return map2; }

Or you don't expose the raw Maps, but just offer a few wrapper methods
that call methods on your two maps.

public boolean put1( String s, Thing t)
{
return map1.put( s, t );
}
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,807
Latest member
ryef

Latest Threads

Top