Will,
Comments below.
Will Horn wrote:
I'm
also interested in an enhanced API - were there any proposals.
Nope.
Here is what I did:
* I created a new plugin com.example.model.validation with a dependency
on com.example.model (my EMF model)
* I created a class ModelValidator that subclasses the generated one
and overrides getEcoreResourceLocator.
You could have done it directly in your generated one?
The
ResourceLocator returned looks in the current plugin
(plugin.properties) for strings and falls back to EcorePlugin if none
are found (i.e. MissingResourceException is thrown).
Note that you could modify your generated plugin so that it directly
delegates to the Ecore plugin by modifying the constructor to mention
the Ecore plugin as a resource locator.
* I
created a class ModelDiagnostician that subclasses Diagnostician and
calls eValidatorRegistry.put(ModelPackage.eINSTANCE, new
ModelValidator()) in the constructor to hook in the ModelValidator
class.
This makes me think you should have modified the base validator.
* I
overrode getFeatureLabel and getObjectLabel in my ModelDiagnostician to
use the generated human friendlier names in the com.example.model.edit
plugin.
That's what the validate action does too, i.e., exploits the label
providers when they are available.
Now if I use ModelDiagnostician to validate EObjects in my model, I can
completely customize the messages (thanks to being able to review the
source code in EObjectValidator).
Isn't open source great. :-P
There are a few issues I'm still dealing with, however. First, I would
like to have different messages for different situations. For example,
a Problems view that lists all of the validation issues probably needs
more description than a control decorator on a dialog box. In the
first case, I might want to say "The 'Author' attribute is missing on
Book ABC." whereas in the second case when Book ABC is being edited in
a dialog box "'Author' is required." is sufficient.
Yes, this context issue is a bit tricky. When you have a message
showing directly for the applicable object it's kind of pointless to be
explicit about the context.
To do this, I think the best solution is to have more information on
the Diagnostic so the message can be formatted however the context
would like. I could create another plugin (or maybe have two
properties files), but it seems I would have to use two separate
validation runs on the same object.
Are you sure that the objects in the actual diagnostic wouldn't allow
you to compose contextual information (about eObject) separate from the
rest of the message?
diagnostics.add
(new BasicDiagnostic
(Diagnostic.ERROR,
DIAGNOSTIC_SOURCE,
EOBJECT__EVERY_MAP_ENTRY_UNIQUE,
getEcoreResourceLocator().getString
("_UI_DuplicateMapEntry_diagnostic",
new Object []
{
getFeatureLabel(eReference, context),
i,
index
}),
new Object [] { eObject, eReference, entry, eMap.get(index) })); |
The second issue is that I would prefer something more generic that I
could use on multiple models/packages at once. In other words to be
able to pass any EObject into something like Diagnostician.validate and
to get the results. I think this would require a way to
change/customize the ResourceLocator without subclassing.
Perhaps this could be done external to the diagnostics themselves? A
given object might have hundreds of errors so perhaps grouping by
context would allow the contextual message to avoid duplication.
I suppose another approach would be to delegate through another utility
method that always passes eObject, which in turns fetches the resource
locator and composes the message without that eObject, i.e., a bit of
refactoring.
Any advice is greatly appreciated!
Maybe some of what I said helped. If a bit of refactoring would be
better, that seems reasonable too. (We just don't want to break any
existing APIs is the only rule to constrain us.)
-Will
Ed Merks wrote:
Eric,
Yes, all good ideas will be taken into consideration. We often
refactor things to make overrides easier once we understand the desired
usage patterns. I hadn't really thought so much about replacing
messages, only about controlling the substitutions in them...
Eric Rizzo wrote:
Ed Merks wrote:
Eric,
I guess you can't. It's really all just one constraint with different
messages to try to be more helpful to pin point in what why the
multiplicity constraint is violated.
It is a bit of a hack, but I found that I can take the
ESructuralFeature (from getData()) and ask it isMany() - if true I use
one message, if false I assume the Diagnostic is about a missing
required attribute and use a different message for that.
If I entered a feature request to provide API in EObjectValidator to
more easily override the message texts, is that something that would at
least be considered? I've got an idea for the actual API.
Eric
Eric Rizzo wrote:
Eric Rizzo wrote:
Ed Merks wrote:
Specializing messages is a little
like wanting to alter the messages that JDT produce. Also keep in mind
that the Diagnostic itself has enough details that you could use those
to produce your own message external to the validator code. I.e., you
have access to the source, the constraint code within the source, and
all objects involved in the problem.
Shortly after my last post, I discovered that. I am customizing
MarkerHelper to modify the Marker messages instead of messing around
with the Diagnostic messages.
I spoke too soon - I'm not so sure in MarkerHelper.composeMessage()
that I have enough information in all cases. The example I'm facing now
is how to tell the difference between a feature has too many values, a
feature that has not enough values, or a required feature has no value.
All of those scenarios seem to produce an identical Diagnostic, so how
can I distinguish them?
Eric
|