Check field errors in word references with VSTO - vsto

How can I check if some fields in my word have errors? I have a large document that contains many references to other chapters or images. When those chapters or images are missing in the document, the fields containing those references will display Error! Reference Source Not Found instead of the reference.
The problem is, that I need to create an algorithm that will check for those reference errors, no matter what the locale and language of the file is. The problem is, that this field error is localized in the language of the system of the user who uses the word.
How can I do this? Is there any property on Field that can be used to check if the source is available?
Currently, I check for errors in the fields by using the result text of the field:
Int32 fieldErrors = 0;
foreach (Word.Field field in doc.Fields)
{
field.Update();
if (field.Result.Text.StartsWith("Error!"))
++fieldErrors;
}
Unfortunately, this will only work in english word instances.

In the documentation for Field types it is seen that a Field instance has an Update() method that returns a bool. The documentation does not state what the semantic meaning of the return value is, however, by doing a short empirical study I found that the method returns true if the Update() succeeded and false if the update did not succeed. This means that in order to find fields with errors you can do something like:
var fieldsWithErrors = new List<Field>();
foreach (Field field in document.Fields)
{
if(!field.Update())
fieldsWithErrors.Add(field);
}
... or shorter with LINQ:
var fieldsWithErrors = document.Fields.Cast<Field>().Where(field => !field.Update()).ToList();
Another (and faster) approach would be to use the Update() method exposed by the Fields collection.
var indexOfFirstError = document.Fields.Update();
... the method returns the index of the first field with an error. If no errors are found, the method returns 0.
For complete documentation please see the MSDN references:
Field.Update()
Fields.Update()
Field members
Fields members

Related

How do I require certain instance variables be provided at object creation?

Let's say I have a type of object in my game called oCharacter. All characters must have names, so I want to provide one when I construct the object. I can do that by using the _variables argument of instance_create_layer:
instance_create_layer(0, 0, "Instances", oCharacter, { name: "George" });
I could even make sure that I don't forget to do this by making a "constructor" function for characters and only instantiating them using that:
function character_create(_x, _y, _name) {
return instance_create_layer(_x, _y, "Instances", oCharacter, { name: _name });
}
But this approach has two problems.
The first is that I or another developer might forget about this convention and instantiate a character directly using instance_create_layer, forgetting to pass a name and setting up a runtime error further down the road.
The second (related) issue is that Feather doesn't know about this convention, so my Feather window is full of error messages about references to instance variables that aren't declared in the Create event - but I don't see how I can declare these variables in the Create event, as I'm expecting their value to be provided by the creator.
Is there some way of doing this that addresses these issues?
The first problem is just about setting rules about the code conventions within your team, if your team does not know about these conventions you want them to follow, then you should tell it them in a meeting.
For the second problem: Maybe you could create an empty/nullable variable in the Create Event? I'm afraid I'm not familiar with Feather
Personally I would do two things for this.
Create development standards for the team and put them in something like a Word document, wiki page, onenote, whatever makes the most sense for your team.
I would use a function to create the instance of the object (like you're doing there), and have some simple validation checks inside of the create event itself that will cancel it's creation (something like a guard clause) and output a debug message with a reminder.
It's not the most elegant solution but that should do the trick (assuming you haven't found something else by now haha)

How to verify an instance of a List is not another List instance?

I have a list
var theDataList: List<Data> // populated with some data
and made a copy of it
val copy = theDataList.toMutableList()
downstream in the code it would like to verify whether it is the copy one or the original one
the .hashCode() returns same for both
If just want to use Log to print out, how to do it?
the Log.d("+++", "theDataList: ${theDataList.hashCode()}, copy: ${copy.hashCode()"}) print out same number.
And Log.d("+++", "copy: ${copy}") prints out the list content
Problem:
The hash code for both lists is the same because it is based on the data in the list, which is the same.
Solution:
What you actually want is to compare the references of both lists. You can do that with Kotlin's referential equality operator ===.
theDataList === copy // false
There is no ID/hash you can rely on to identify an object on the JVM the way you want. For more info take a look here.
Use the === operator to compare references are the same (not calling equals method)

Attempt retrieval of value from VBA dictionary and raise error if key not in use?

I've used dictionaries (Whether they were called that or not) in a number of other languages, but there's always been a method that can be called with on parameter that either:
A) Returns the associated value if the parameter is in use as a key, or
B) Indicates in some way that the parameter is not used as a key
I've been forced into a position where I have to learn excel/VBA and used the collections class for all of about five minutes before the lack of an .exists method led me to look for something else. The general consensus seems to be that the scripting.Dictionary class is the VBA equivalent of associative arrays/dictionaries/hashtables in other languages.
The one thing I don't like the look of though is that the only way I can see of retrieving the value associated with a given key is to use the .items property (either explicitly, or via scripting.Dictionary("key")). But rather than doing anything to indicate the issue if key is not in use in the dictionary, it adds it.
I know I can use a if structure with .exists being the test to achieve the same functionality, and can write my own function that raises an error if the exists test fails, but it seems a lot of stuffing around to achieve what is core functionality in Python (raises KeyError), PHP (raises a Notice), Java (Maps return null - although that is not necessarily ideal in the case of HashMaps where null actually is a valid value - but it does work as an indicator for HashTables).
So is there any way of attempting to retrieve a value by key that will do something (ideally throw an error) if the key is not in use, rather than silently adding it? Google hasn't provided any answers - but maybe I'm just not phrasing the search well.
I find it inconvenient too that Dictionary adds the key when you access a non-existing key.
Just use Collection and write the missing Exist function yourself, e.g.
Function ExistsInCollection(ByVal c As Collection, ByVal key As Variant) As Boolean
On Error GoTo not_exists
c.Item key
ExistsInCollection = True
not_exists:
End Function

Why does Javassist insist on looking for a default annotation value when one is explicitly specified?

I am using Javassist to add and modify annotations on a package-info "class".
In some cases, I need to deal with the following edge case. Someone has (incorrectly) specified an #XmlJavaTypeAdapters annotation on the package-info package, but has not supplied a value attribute (which is defined as being required). So it looks like this:
#XmlJavaTypeAdapters // XXX incorrect; value() is required, but javac has no problem
package com.foobar;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
In Javassist, this comes through slightly oddly.
The javassist.bytecode.annotation.Annotation representing the #XmlJavaTypeAdapters annotation does not have a member value (getMemberValue("value") returns null), as expected.
It is of course possible to add a value() member value, and that is what I've done:
if (adaptersAnnotation.getMemberValue("value") == null) {
final ArrayMemberValue amv = new ArrayMemberValue(new AnnotationMemberValue(constantPool), constantPool);
adaptersAnnotation.addMemberValue("value", amv);
annotationsAttribute.addAnnotation(adaptersAnnotation);
}
In the code snippet above, I've created a new member value to hold an array of annotations, because the value() attribute of #XmlJavaTypeAdapters is an array of #XmlJavaTypeAdapter. I've specified its array type by trying to divine the Zen-like documentation's intent—it seems that if you supply another MemberValue that this MemberValue will somehow serve as the array's type. In my case I want the type of the array to be #XmlJavaTypeAdapter, which is an annotation, so the only kind of MemberValue that seemed appropriate was AnnotationMemberValue. So I've created an empty one of those and set it as the array type.
This works fine as far as it goes, as long as you stay "within" Javassist.
However, something seems to have gone wrong. If I ask Javassist to convert all of its proprietary annotations into genuine Java java.lang.annotation.Annotations, then when I try to access the value() attribute of this #XmlJavaTypeAdapters annotation, Javassist tells me that there is no default value. Huh?
In other words, that's fine—indeed there is not—but I have specified what I had hoped was a zero-length array (that is, the default value shouldn't be used; my explicitly specified zero-length array should be used instead):
final List<Object> annotations = java.util.Arrays.asList(packageInfoClass.getAnnotations());
for (final Object a : annotations) {
System.out.println("*** class annotation: " + a); // OK; one of these is #XmlJavaTypeAdapters
System.out.println(" ...of type: " + a.getClass()); // OK; resolves to XmlJavaTypeAdapters
System.out.println(" ...assignable to java.lang.annotation.Annotation? " + java.lang.annotation.Annotation.class.isInstance(a)); // OK; returns true
if (a instanceof XmlJavaTypeAdapters) {
final XmlJavaTypeAdapters x = (XmlJavaTypeAdapters)a;
System.out.println(" ...value: " + java.util.Arrays.asList(x.value())); // XXX x.value() throws an exception
}
}
So why is Javassist looking for a default value in this case?
My larger issue is of course to handle this (unfortunately somewhat common) case where #XmlJavaTypeAdapters is specified with no further information on it. I need to add a value member value that can hold an array of #XmlJavaTypeAdapter annotations. I can't seem to figure out how to accomplish this with Javassist. As always, all help appreciated.
For posterity, it appears that in this particular case (to avoid a NullPointerException and/or a RuntimeException), you need to do this:
if (adaptersAnnotation.getMemberValue("value") == null) {
final ArrayMemberValue amv = new ArrayMemberValue(constantPool);
amv.setValue(new AnnotationMemberValue[0]);
adaptersAnnotation.addMemberValue("value", amv);
annotationsAttribute.addAnnotation(adaptersAnnotation);
}
Note in particular that I deliberately omit the array type when building the ArrayMemberValue (including one of any kind will result in an exception). Then I explicitly set its value to an empty array of type AnnotationMemberValue. Any other combination here will result in an exception.
Additionally, and very oddly, the last line in that if block is critical. Even though in this particular case the annotation itself was found, and so hence was already present in the AnnotationsAttribute, you must re-add it. If you do not, you will get a RuntimeException complaining about the lack of a default value.
I hope this helps other Javassist hackers.

Why does resolveBinding() return null even though I setResolveBindings(true) on my ASTParser?

I am writing an Eclipse plug-in that uses JDT AST's ASTParser to parse a method. I am looking within that method for the creation of a particular type of object.
When I find a ClassInstanceCreation, I call getType() on it to see what type is being instantiated. I want to be sure that the fully-resolved type being dealt with there is the one I think it is, so I tell the resultant Type object to resolveBinding(). I get null back even though there are no compilation errors and even though I called setResolveBindings(true) on my ASTParser. I gave my ASTParser (via setSource()) the ICompilationUnit that contains my method, so the parser has access to the entire workspace context.
final IMethod method = ...;
final ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
parser.setSource(method.getCompilationUnit());
parser.setSourceRange(method.getSourceRange().getOffset(), method.getSourceRange().getLength());
parser.setKind(ASTParser.K_CLASS_BODY_DECLARATIONS);
final TypeDeclaration astRoot = (TypeDeclaration) parser.createAST(null);
final ClassInstanceCreation classInstanceCreation = walkAstAndFindMyExpression(astRoot);
final Type instantiatedType = classInstanceCreation.getType();
System.out.println("BINDING: " + instantiatedType.resolveBinding());
Why does resolveBinding() return null? How can I get the binding information?
Tucked away at the bottom of the overview of ASTParser.setKind(), carefully hidden from people troubleshooting resolveBinding() and setResolveBindings(), is the statement
Binding information is only computed when kind is K_COMPILATION_UNIT.
(from the online Javadoc)
I don't understand offhand why this would be the case, but it does seem to point pretty clearly at what needs to be different!