Eclipse: Trying to convert CCombo "display" value to "storage" value
I'm building my plugin in Helios SR2. It'd be Nice to support Galileo, but I'm not overly worried about it at this point. Windows 7: 64 bit, 64-bit JVM (1.6_21 IIRC).
I have an swt.custom.CCombo
box filled with the display values of a list of entries. I have a map of "display value" -> "storage value".
I want to store the storage value, and display the display value. Go figure.
I'm using databinding with BeanObservables, IObservables, a DataBindingContext, all that jazz.
My current approach (that isn't working or I wouldn't be asking) is to create my own UpdateValueStrategy
with a custom IConverter
that'll internally map between the two.
I'm currently trying to extend org.eclipse.core.databinding.conversion.Converter
, because IConverter is marked with @noimplement
and @noextend
. The @noimplement
states that clients should extend Converter
rather than implementing IConverter directly (even though Converter is fairly trivial).
Sadly, Eclipse's Java compiler is telling me that's a no-no:
Access restriction: The type Converter is not accessible due to restriction on required library {install}\plugins\org.eclipse.core.databinding_1.3.100.I20100601-0800.jar
In the relevant ".api_description", I see the following XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component name="org.eclipse.core.databinding_1.3.100.I20100601-0800" version="1.2">
<plugin id="org.eclipse.core.databinding_1.3.100.I20100601-0800"/>
<package name="org.eclipse.core.databinding" visibility="1">
<type name="ObservablesManager" restrictions="2"/>
<type name="UpdateListStrategy" restrictions="0">
<method name="useMoveAndReplace" restrictions="8" signature="()Z"/>
<开发者_运维问答/type>
</package>
<package name="org.eclipse.core.databinding.conversion" visibility="1">
<type name="IConverter" restrictions="3"/>
</package>
</component>
Rooting around thanks to Google Code, I see that visibility="1"
means a public API. Okay, great.
restrictions="3"
on the other hand, means @noextend @noimplement. Sound familiar? Okay, great.
But it seems the restrictions on IConverter are rubbing off on Converter, making it impossible to use. I cannot extend Converter, nor may I call super(blah, blah)
from my constructor. Interestingly enough, the compiler is not complaining about my implementation of public Object convert(Object fromObject)
even though Converter doesn't have one of its own so one might think the IConverter
restrictions would apply.
Clearly not.
Does anyone have
- An entirely different approach?
- Some means to beat this access restriction stuff into submission, preferably in a local kind of way so I don't do something dumb elsewhere.
I found the "restricted access" setting for the compiler and have switched it to "warn" rather than "error". However, I'm hoping there's something a bit less global I could do. I'll proceed with this in the mean time, but an alternative would be nice.
How Strange.
Okay, when I tried to use the auto-correct "include org.eclipse.core.databinding_1.3..." nothing happened. I ass-u-me'd that it was correctly included as a plugin dependency and didn't fix the error.
During this time, that plugin's jar appeared in my plugin project's "Plug-in Dependencies" folder, and I was able to view its source. One would think at that point that the plugin was correctly included in the plugin.xml
One would be wrong.
I manually added ...core.databinding_1.3... to my plugin dependencies and the errors Went Away.
So it seems this is a bug in the autocorrect rather than in the API restriction code.
AH! I had org.eclipse.core.databinding in my Imported Packages list. That must have thrown things off.
So now you know. And knowing's have the battle. GO CODE!
And speaking of code. Here's what I'm doing (more or less):
enum MapValueDirection {
VALUE_TO_KEY,
KEY_TO_VALUE
};
private class MappingConverter extends Converter {
Map<String, String> map = null;
public MappingConverter( Map<String, String> map_, MapValueDirection dir) {
super(String.class, String.class);
if (dir == MapValueDirection.VALUE_TO_KEY) {
map = reverseMap(map_);
} else {
map = map_;
}
}
private Map<String, String> reverseMap(Map<String, String> map_) {
Map<String, String> reversedMap = new TreeMap<String, String>();
Set<Entry<String, String>> entries = map_.entrySet();
for (Entry<String, String> curEnt : entries) {
reversedMap.put(curEnt.getValue(), curEnt.getKey());
}
return reversedMap;
}
/* (non-Javadoc)
* @see org.eclipse.core.databinding.conversion.IConverter#convert(java.lang.Object)
*/
public Object convert(Object fromObject) {
if (map != null && fromObject != null && String.class.equals(fromObject.getClass())) {
Object newVal = map.get(fromObject);
if (newVal == null) {
newVal = fromObject;
}
return newVal;
}
return fromObject;
}
}
/**
* And this is were the actual work gets done.
*/
public void bindBean(Object bean, PropertyDescriptor prop) {
Control curControl = getControl(prop.getPropertyType());
IObservableValue uiElement = getObserver(prop, curControl);
IOvservableValue modelElement = BeanObservables.observValue(bean, prop.getName());
// "display" = key, "storage" = value
Map<String, String> profileFlds = getProfileFields();
UpdateValueStrategy toStorage = new UpdateValueStrategy();
toStorage.setConverter( new MappingConverter( profileFlds, MapValueDirection.KEY_TO_VALUE));
UpdateValueStrategy toDisplay = new UpdateValueStrategy();
toDisplay .setConverter( new MappingConverter( profileFlds, MapValueDirection.VALUE_TO_KEY));
m_bindingContext.bindValue( uiElement, modelElement, toDisplay , toStorage);
}
My actual code is a bit more complex than that, but you get the idea. I suspect it's not terribly efficient, but it works well within the whole data binding framework, conceptually speaking (based on my admittedly limited experience).
It should be fairly trivial to make a Generic version of MappingConverter, but I'll leave that as an Exercise For the Reader.
精彩评论