I have the below XML,
<outer.element>
<bold>
<csc>CSCTEXT</csc>
REST OF THE TEXT
</bold>
</outer.element>,
i try to retrieve the text inside the <outer.element> element tag and sending it to a java method. i get the below exception,
XPathException: A sequence of more than one item is not allowed as the second argument of class:method() ("CSCTEXT", "REST OF THE TEXT").
if i use an array in the java method signature i get the below exception,
"Cannot convert value class net.sf.saxon.tinytree.TinyTextImpl of type text() to class java.lang.String"
how do i send a single concatenated value (class:method() ("CSCTEXT REST OF THE TEXT")) to the java method.?
Thank you in advance.
The first error:
XPathException: A sequence of more than one item is not allowed as the second argument of class:method() ("CSCTEXT", "REST OF THE TEXT").
means that you're calling your Java method with a sequence of values when it is only expecting one.
Using collection classes in the signature of your Java method will tend to mean that the individual items don't get converted, hence the second error "Cannot convert...".
One solution to that is to do the conversion yourself in the function call (for example, by calling the data() function). Or do it in the Java method (call the getStringValue() method on the supplied items).
If I am writing extension functions in Java specifically to be called from XPath/XSLT, then I will nowadays uses Saxon-specific classes in the method signature, for example ZeroOrMore<StringValue>. Saxon will then use exactly the same calling conventions as it uses for native XSLT/XPath functions (for example, implicit atomization) and your called code can do any further conversion needed itself.
Related
I have a 3rd party library (Springfox, but it doesn't really matter which one here) with a method with signature tags(Tag first, Tag... remaining). Because I need to feed about a dozen Tags into this method, I'd like to split that off into a separate method for readability and maintainability:
public Tag[] generateTags(){
return new Tag[]{
new Tag("Tag1", "Tag 1 Description"),
// other tags
};
}
The problem is that I can't simply feed a Tag[] array into the 3rd party library method, because it doesn't match the method signature for tags(Tag, Tag...). I'm getting the error
The method tags(Tag, Tag...) in the type Docket is not applicable for the arguments (Tag[])
at compile time. This is of course fully expected, though I find it somewhat weird that the Java compiler doesn't recognize that the varArgs argument is of the same type as the argument before it and allows the array to fill both of them.
Beyond the simple solution of defining the first tag inside the tags() calls and then defining the other tags in the external method, are there any other solutions for this?
You could write a wrapper method to solve your issue. Just split the first Tag from your Array and feed the the rest into the second argument:
public void tagsWrapper(Tag[] tags){
Tag first = tags[0];
Tag[] other = Arrays.copyOfRange(tags, 1, tags.length);
tags(first, other);
}
I'm writing a custom rule for SonarQube for java, I want to check if the value of an argument is qualified. For example, I want to know if the String fit the specific pattern. I can only test if the argument is a String, but I can not get the exact value. Does the API allows me to do so?
For example, for the code below
log.error("errorID:210134 It's an error");
Can I get the argument and test if the string contains errorID?
Besides, can I get what variable did the method invocation?
For example, for the code below
log.error("errorID:210134 It's an error");
How can I know that log is an Object of the class Logger?
The following should do the trick:
When looking at the argument of the method invocation, check if its kind is a STRING_LITERAL, then cast the argument into a LiteralTree. From there, you will be able to access its value, as a String (Note that it will contain the double quotation marks).
To check if the invocation was done on a variable, get the methodSelect() expression tree from the method invocation. If its kind is a MEMBER_SELECT, cast it to MemberSelectExpressionTree. From there, check if the kind of the expression() is an IDENTIFIER. If it's the case, then you will be able to get the IdentifierTree and its associated symbol. You will then be able to say if the symbol calling the method is a variable or not, check its type, etc.
I'm trying to call methods that take no arguments on a Java class, but when I do, I get reflection warnings saying that "reference to field [methodName] can't be resolved".
According to this the Clojure docs on Java interop (http://clojure.org/java_interop), "The instance member form works for both fields and methods." How can I tell it that I want a method? It seems to assume that since I'm not passing args that I want a field.
If there are both fields and methods, then the (.member instance) form will invoke the method (which is more common). If you want to force access to the field, the (.-field instance) form will only retrieve the field value.
If you have an example that is not working as you expect, it would be helpful to see the code or error.
There are some circumstances where if the Clojure compiler cannot find the method (by an unknown instance class or parameter types), the error message will indicate it was looking for a field, but this is just an artifact of the order it's evaluating options. Sometimes turning on reflection warnings will help pinpoint the issue better.
Here's an example. It creates a Java class - StringBuilder, initialised with a string. A method with no parameters - reverse - is then called on it and the results are converted to a String by calling the toString method.
user=> (def sb (java.lang.StringBuilder. "Hello World"))
;; #'user/sb
user=> (.toString (.reverse sb))
;; "dlroW olleH"
user=> (.toString (.reverse sb))
;; "Hello World"
user=>
A StringBuilder object is mutable so it retains its state, as a result, the second reverse rolls back the first one. This is not very Clojure like so it has to be used with caution.
Someone asked me what the difference between the two method parameters and why you would use the ... over specifically assigned array.
putMessage(byte ...send)
putMessage(byte[] send)
I couldn't answer them with confidence and couldn't remember what the ... is called.
The ... in your first example are called varargs. Your second example has an array argument. Varargs are a convenience for times when you want to hard code a variable number of arguments to a method but don't want to manually create an array to hold them. It's a shorthand notation. Consider this:
putMessage(0b00100101, 0b00100101, 0b00100101); // varargs
vs. this:
putMessage(new byte[] { 0b00100101, 0b00100101, 0b00100101 }); // array
The first example is less cluttered and more readable.
The parameters with ellipses are generally referred to as "varargs" if you want to google that.
Using varargs allows you to call a method with variable number of arguments without having to specify an array e.g.
public void printStr(String ...strings) {
for (String s : strings) {
System.out.println(s);
}
}
> printStr("Hello", "World")
Hello
World
So varargs allow a certain degree of convenience, but there are downsides - the varargs parameter must be the last parameter in the method signature, and thus you cannot have more than one varargs parameter to a method. If you want to pass multiple arrays to a method you have to use arrays, not varargs.
Another reason you might see arrays in some places where you might expect varargs is that varargs were only introduced in Java 5 - older code and code that needs to be backwards compatible will still be using arrays even where it might make more sense conceptually to use varargs.
The advantage of using varargs in the method signature is flexibility - there are some situations where the caller will have an array ready anyway and some where they will just have several arguments. Varargs will accept either the array or each variable as a separate argument, saving the caller the trouble of instantiating and populating an array.
The first one is with Varargs.
In short
A. First can be used to call with single byte type arg, 2 byte args.. or many args or an array.
B. second will be used with array only.
The ellipsis (three dots) indicates that you are using "varargs".
See http://download.oracle.com/javase/1,5.0/docs/guide/language/varargs.html for more details.
Inside the method, you access the elements of "send" as an array. The two methods are the same in that regard. The convenience is for the caller. In the second putMessage, the caller is compelled to create an array of bytes to pass to putMessage. In the first putMessage, the caller can simply say "putMessage(byte1, byte2)" or "putMessage(byte1, byte2, byte3)" or "putMessage(byte1)" -- variable number of arguments, or varargs.
The ellipses (...) allow you to inline N parameters of a type to a function call without having to define an array first. In the end you do simply get an array of parameters but it's basically shorthand or syntactic sugar. Also your client code might be a little cleaner and more declarative with the ellipses syntax... though it could easily go the other way and become mucky and unreadable.
Here's a great example of the ellipses syntax (variable length argument lists.) While looking at the sample consider what the client code (in the main function) would look like if an array was used instead of a variable length argument list.
I have a method that looks like this on Java:
public void myMethod(Object... parms);
But I can't call this method as expected from the scripts.
If, in ruby, I do:
$myObject.myMethod(42);
It gives me org.jruby.exceptions.RaiseException: could not coerce Fixnum to class [Ljava.lang.Object
If I try the following in Javascript:
myObject.myMethod(42);
Then it gives me sun.org.mozilla.javascript.internal.EvaluatorException: Can't find method MyClass.test(number). (#2) in at line number 2
Of course, if I change the signature to take one single object then it works.
I assume that this is because someone along the line does not know how to convert, say Integer to Integer[] with the value at the first position.
I believe something like myMethod({42, 2009}) would work in Ruby, but this seems ugly - I wanted to be able to just do myMethod(42, 2009) to make it less confusing, specially for other languages. Is there any better workaround for this?
Thanks.
Java internally treats the variable-length argument list as an array whose elements are all of the same type. That is the reason why you need to provide an array of objects in your JRuby script.
It works like this:
myMethod [42, 2009].to_java
The to_java method constructs a Java array from a Ruby array. By default, to_java constructs Object arrays as needed in this case. If you need a String array you would use
["a","b","c"].to_java(:string)
More on this at the JRuby wiki
It seems like this is a known bug in jruby. See method dispatch on Java objects / classes should try to find a matching varargs method and NameError thrown when trying to pass argument to a Java method that is defined as having variable length arguments.
According to the link Rhino does support vararg.
Varargs are handled by the compiler as an Object[] which is what the error message describes.
I do not have JRuby experience, but does it work if you have an array argument?