In my Java SWT application I'm hosting an 3rd party ActiveX control. I'm using OleClientSite to do this.
// Ah, this works. :-)
OleAutomation comObject = new OleAutomation(...);
There are 2 easy little functions I want to call from Java. Here are the COM function definitions:
[id(5)]
void easyFoo([in] int blah);
[id(20)]
void problemFoo([in] VARIANT floatArray);
Easy, right? Here's my pretend code:
// Ah, this works. :-)
OleAutomation comObject = new OleAutomation("Some3rdPartyControlHere");
// Call easyFoo(42). This works. :-)
int easyFooId = 5;
comObject.invoke(easyFooId, new Variant[] { new Variant(42) });
// Call problemFoo(new float[] { 4.2, 7.0 }). This doesn't work. :-(
int problemFooId = 20;
comObject.invoke(problemFooId, [ACK! What goes here?]);
The problem is on the last line: how do I pass a float array to the 3rd party COM object? HELP!
You need to pass a float array. In COM terms, that mean s a VARIANT with vt set to VT_R4|VT_ARRAY. An array of variants may not work as the document does not say it can accept an array of variants (VT_VARIANT |VT_ARRAY). In java you should be able to use float[] as the parameter type. If not you can always call the Windows API to construct a safe array of desired type.
I suspect there is no constructor that takes a float[] because VARIANTs don't have a float array member.
I think what you need to do to make this work is pack up your floats into a SAFEARRAY (ick; and I have no idea how to create one in Java).
Alternatively, you may try serializing your array to raw bits and use the BYTE* member of the VARIANT struct, and pass an int that has the count of bytes so you can accurately de-serialize on the other side (and I assume this is all in the same process and thread, otherwise it gets harder).
[id(20)]
void problemFoo([in] VARIANT bytes /* VT_BYREF|VT_UI1 */, [in] VARIANT byteCount /* VT_UI4 */);
What's wrong with creating an array of Variant and filling it with your float array values?
Variant[] problemFooArgs = new Variant[myFloats.length];
for( int i=0; i<myFloats.length; i++)
{
problemFooArgs[i] = new Variant(myFloats[i]);
}
If it really needs only one argument (an array of float), you could try one level of indirection:
Variant[] problemFooArgs = new Variant[1];
Variant[] myFooArgs = new Variant[1];
for( int i=0; i<myFloats.length; i++)
{
myFooArgs [i] = new Variant(myFloats[i]);
}
problemFooArgs[0] = myFooArgs;
If the simple approach does not work and you do need a SAFEARRAY, you could try and create one after the example "Reading and writing to a SAFEARRAY", using the constants of org.eclipse.swt.internal.win32.OS. But it seems for char[] only.
Other source of inspiration for creating the relevant SAFEARRAY:
class SafeArray of project com4j (and its associated class, like Variant)
Related
In the javassist API it seems there is no direct way to add anything by hand in the CodeAttribute property.
Given this example:
CtMethod m;
m.getMethodInfo().getCodeAttribute().setAttribute(???);
this seems to be the only way to alter attributes. But, neither is possible to retrieve the original attributes and modify them (it returns a list od AttributeInfo), nor a public constructor exists for StackMapTable, which seems to be the only accepted input.
Anyone knows how to do something like this?
The CodeAttribute object is responsible for holding the bytecode that represents the method flow. You can use it to iterate the bytecode that represents the method logic.
This basically means that it represents the compiled method itself. I know you can use this object to manually modify the bytecode itself for example deleting all the instruction between two lines:
// erase from line 4 to 6
int startingLineNumber= 6;
// Access the code attribute
CodeAttribute codeAttribute = mymethod.getMethodInfo().getCodeAttribute();
LineNumberAttribute lineNumberAttribute = (LineNumberAttribute) codeAttribute.getAttribute(LineNumberAttribute.tag);
// Index in bytecode array where we start to delete
int firstIndex = lineNumberAttribute.toStartPc(startingLineNumber);
// Index in the bytecode where the first instruction that we keep starts
int secondIndex = lineNumberAttribute.toStartPc(startingLineNumber+2);
// go through the bytecode array
byte[] code = codeAttribute.getCode();
for (int i = firstIndex ; i < secondIndex ; i++) {
// set the bytecode of this line to No OPeration
code[i] = CodeAttribute.NOP;
}
However this could be really tricky and can get out of hands quite easily.
What I suggest to do is to just create a new CodeAttribute rom scratch and substitute it into you method in order to avoid unplesant surprises:
ClassFile cf = ...;
MethodInfo minfo = cf.getMethod("yourMethod");
Bytecode code = new Bytecode(cf.getConstPool());
// insert your logic here
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
code.setMaxLocals(1);
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
However thi method also may be quite risky since you are handling directly bytecode. Probably the best would be just to delete your method and add a new one with your logic instead.
I'm trying to apply a Dye color into an existing ItemStack, how can I do this without using deprecated methods and creating an new stack?
I tried the following code but it's resulting in a normal ink sack.
ps: I'm creating an stack in the first line only as example.
final ItemStack stack = new ItemStack(Material.INK_SACK);
Dye dye = new Dye();
dye.setColor(DyeColor.LIME);
stack.setData(dye);
edit: Added final to stack variable to show that it cannot be replaced by a new stack.
I've found a way to do this, but it is nowhere near as efficient as using a deprecated method. Here it is with my own personal thought process along the way.
The problem with your current attempt is the interior of the setData(MaterialData) method.
public void setData(MaterialData data) {
Material mat = getType();
if (data == null || mat == null || mat.getData() == null) {
this.data = data;
} else {
if ((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class)) {
this.data = data;
} else {
throw new IllegalArgumentException("Provided data is not of type " + mat.getData().getName() + ", found " + data.getClass().getName());
}
}
}
This method works as a simple setter that handles null values and prevents incorrect data types. The problem here should be quite visible though. Wools and dyes don't store their info in MaterialData, they store it in their durability. The durability of a Colorable object determines its color. Being that this is the case, you will need to modify the durability in order to do anything to the color. The only place you can set the durability outside of the constructor is the setDurability method. This doesn't take a MaterialData, only a short. Thus our options are the following: Construct a new ItemStack, or gain non-deprecated access to a usable short value. By your criteria, we move to the latter.
First point of entry, the DyeColor class. If we can't find the short value here, it will at least be supplied from here to another class. Looking at the source gives us a grim reminder of just how rooted in deprecation the problem is.
There is one hacky solution using DyeColor alone, but it's not version proof incase of changes. The Enum.ordinal() method will return the ordinal value of an enum. This is the numerical value of the order it was defined. Starting from index zero, it will match the wool data values, but needs to be inverted for dyes, something you are trying to make universal. The option is there though.
So DyeColor is out of the question, but it got me thinking. The Dye class as a MaterialData works perfectly fine when using the toItemStack() method. Maybe we could use that. Turns out you can! It will require creating a new Itemstack, but we will use the new ItemStack to access data for the original one. Firstly, we create the MaterialData like you did above.
Dye dye = new Dye();
dye.setColor(DyeColor.LIME);
Next, convert the Dye into an Itemstack using the toItemStack() method.
ItemStack tempStack = dye.toItemStack();
Now hold on, why does this work? Well you see, the Dye.setColor(DyeColor) method has an internal implementation of the following:
public void setColor(DyeColor color) {
setData(color.getDyeData());
}
It uses a deprecated method, but because it's wrapped in a DyeColor call, it's not deprecated to the plugin user. Please note: THIS IS PERFECTLY ACCEPTABLE! Many of Bukkit's calls using Material as a parameter actually just call the deprecated method with the type id associated to it. It's perfectly valid to call those methods though. Also note that the setData(byte) method is just a simple setter.
Next up, the toItemStack() method.
public ItemStack toItemStack(int amount) {
return new ItemStack(type, amount, data);
}
We can see here that the DyeColor that was converted to a byte is now sent to the ItemStack constructor ItemStack(Material, int, short) as the durability (it automatically casts to a short). This means, we now have the short we require! It's stored in the durability of tempStack. To top it all off, we do the following.
stack.setDurability(tempStack.getDurability());
stack.setData(dye);
It's over. You have a modified ItemStack with no exposed deprecated methods. You may be asking though why I still call ItemStack.setData(MaterialData). This just ensures that if someone tries to access the DyeColor from the ItemStack's MaterialData it will match up with the durability.
I hope you are satisfied with the fact that it is possible, but I still just recommend using the deprecated methods until they are listed as broken (which usually doesn't happen with Bukkit).
You could try using the Dye(Material) constructor, then appying your DyeColor, and converting the Material to an ItemStack.
Dye dye = new Dye(Material.INK_SACK);
dye.setColor(...);
ItemStack coloredInkSack = dye.toItemStack();
DyeColor.* actually uses wool colors, and Mojang decided to switch dye colors and wool colors around. So, DyeColor.LIME.getData() returns 5, which is lime wool, but lime dye is 10. So you need to use byte data = (byte) (15 - DyeColor.COLOR.getData());
So, here's what your code should look like:
DyeColor color = DyeColor.LIME //or whatever dye color you want
byte data = (byte) (15 - color.getData()); //use byte data = (byte) (color.getData()) if you're coloring wool
ItemStack itm = new ItemStack(Material.INK_SACK, 1, data);
This would give you an ItemStack with 1 lime dye.
If you would really like to use a non-deprecated method, you could make your own enum with their ID's:
public enum CustomDyeColor{
BLACK(0), //ink sack
RED(1),
GREEN(2),
BROWN(3),
BLUE(4), //lapis lazuli
PURPLE(5),
CYAN(6),
LIGHT_GRAY(7),
GRAY(8),
PINK(9),
LIME(10),
YELLOW(11),
LIGHT_BLUE(12),
MAGENTA(13),
ORANGE(14),
WHITE(15); //bonemeal
private byte data;
CustomDyeColor(int i){
this.data = (byte) i;
}
public byte getData(){
return this.data;
}
}
And then you could use your new, non-depricated, custom code to get the data values like this:
CustomDyeColor color = CustomDyeColor.LIME;
byte customData = color.getData();
ItemStack item = new ItemStack(Material.INK_SACK, 1, customData)l
I did it like so:
new ItemStack(Material.STAINED_GLASS_PANE, 1, DyeColor.BLACK.getData()));
With the 1.8.8 Spigot it actually creates 1 black glass pane, although it says the getData() on the color is deprecated.
I think it also works with wool and clay.
I'm translating a Java program into X10 and have run into a couple problems that I was wondering if anyone could help me translate.
Here's one Java segment that I'm trying to translate:
ArrayList<Posting>[] list = new ArrayList[this.V];
for (int k=0; k<this.V; ++k) {
list[k] = new ArrayList<Posting>();
}
And here's what I've done in X10:
var list:ArrayList[Posting]=new ArrayList[Posting](this.V);
for (var k:int=0; k<this.V; ++k) {
list(k)=new ArrayList[Posting]();
}
The line that's generating a mess of error statements is this:
list(k)=new ArrayList[Posting]();
Any suggestions and maybe an explanation on what I'm doing wrong?
Agreed with trutheality. You need to define list as something like Rail[ArrayList[Posting]] :
var list:Rail[ArrayList[Posting]]=new Rail[ArrayList[Posting]](this.V);
Also, as X10 supports type inference for immutable variables, it's often better to use val instead of var and omit the type declaration altogether:
val list = new Rail[ArrayList[Posting]](this.V);
Here is code that should work for you:
val list = new Rail[ArrayList[Posting]](this.V);
for (k in 1..(this.V)) {
list(k)=new ArrayList[Posting]();
}
And you can also do
val list = new Rail[ArrayList[Posting]](this.V, (Long)=>new ArrayList[Temp]());
i.e. use a single statement to create an initialized array.
What are the most common mistakes that Java developers make when migrating to Scala?
By mistakes I mean writing a code that does not conform to Scala spirit, for example using loops when map-like functions are more appropriate, excessive use of exceptions etc.
EDIT: one more is using own getters/setters instead of methods kindly generated by Scala
It's quite simple: Java programmer will tend to write imperative style code, whereas a more Scala-like approach would involve a functional style.
That is what Bill Venners illustrated back in December 2008 in his post "How Scala Changed My Programming Style".
That is why there is a collection of articles about "Scala for Java Refugees".
That is how some of the SO questions about Scala are formulated: "help rewriting in functional style".
One obvious one is to not take advantage of the nested scoping that scala allows, plus the delaying of side-effects (or realising that everything in scala is an expression):
public InputStream foo(int i) {
final String s = String.valueOf(i);
boolean b = s.length() > 3;
File dir;
if (b) {
dir = new File("C:/tmp");
} else {
dir = new File("/tmp");
}
if (!dir.exists()) dir.mkdirs();
return new FileInputStream(new File(dir, "hello.txt"));
}
Could be converted as:
def foo(i : Int) : InputStream = {
val s = i.toString
val b = s.length > 3
val dir =
if (b) {
new File("C:/tmp")
} else {
new File("/tmp")
}
if (!dir.exists) dir.mkdirs()
new FileInputStream(new File(dir, "hello.txt"))
}
But this can be improved upon a lot. It could be:
def foo(i : Int) = {
def dir = {
def ensuring(d : File) = { if (!d.exists) require(d.mkdirs); d }
def b = {
def s = i.toString
s.length > 3
}
ensuring(new File(if (b) "C:/tmp" else "/tmp"));
}
new FileInputStream(dir, "hello.txt")
}
The latter example does not "export" any variable beyond the scope which it is needed. In fact, it does not declare any variables at all. This means it is easier to refactor later. Of course, this approach does lead to hugely bloated class files!
A couple of my favourites:
It took me a while to realise how truly useful Option is. A common mistake carried from Java is to use null to represent a field/variable that sometimes does not have a value. Recognise that you can use 'map' and 'foreach' on Option to write safer code.
Learn how to use 'map', 'foreach', 'dropWhile', 'foldLeft', ... and other handy methods on Scala collections to save writing the kind of loop constructions you see everywhere in Java, which I now perceive as verbose, clumsy, and harder to read.
A common mistake is to go wild and overuse a feature not present in Java once you "grokked" it. E.g. newbies tend to overuse pattern matching(*), explicit recursion, implicit conversions, (pseudo-) operator overloading and so on. Another mistake is to misuse features that look superficially similar in Java (but ain't), like for-comprehensions or even if (which works more like Java's ternary operator ?:).
(*) There is a great cheat sheet for pattern matching on Option: http://blog.tmorris.net/scalaoption-cheat-sheet/
I haven't adopted lazy vals and streams so far.
In the beginning, a common error (which the compiler finds) is to forget the semicolon in a for:
for (a <- al;
b <- bl
if (a < b)) // ...
and where to place the yield:
for (a <- al) yield {
val x = foo (a).map (b).filter (c)
if (x.cond ()) 9 else 14
}
instead of
for (a <- al) {
val x = foo (a).map (b).filter (c)
if (x.cond ()) yield 9 else yield 14 // why don't ya yield!
}
and forgetting the equals sign for a method:
def yoyo (aka : Aka) : Zirp { // ups!
aka.floskel ("foo")
}
Using if statements. You can usually refactor the code to use if-expressions or by using filter.
Using too many vars instead of vals.
Instead of loops, like others have said, use the list comprehension functions like map, filter, foldLeft, etc. If there isn't one available that you need (look carefully there should be something you can use), use tail recursion.
Instead of setters, I keep the spirit of functional programming and have my objects immutable. So instead I do something like this where I return a new object:
class MyClass(val x: Int) {
def setX(newx: Int) = new MyClass(newx)
}
I try to work with lists as much as possible. Also, to generate lists, instead of using a loop, use the for/yield expressions.
Using Arrays.
This is basic stuff and easily spotted and fixed, but will slow you down initially when it bites your ass.
Scala has an Array object, while in Java this is a built in artifact. This means that initialising and accessing elements of the array in Scala are actually method calls:
//Java
//Initialise
String [] javaArr = {"a", "b"};
//Access
String blah1 = javaArr[1]; //blah1 contains "b"
//Scala
//Initialise
val scalaArr = Array("c", "d") //Note this is a method call against the Array Singleton
//Access
val blah2 = scalaArr(1) //blah2 contains "d"
Can someone please give the Java equivalent of the below python (which slices a given array into given parts) which was originally written by ChristopheD here:
def split_list(alist, wanted_parts=1):
length = len(alist)
return [ alist[i*length // wanted_parts: (i+1)*length // wanted_parts]
for i in range(wanted_parts) ]
I don't know any python but can really use the above code in my Java app. Thanks
Maybe something like this:
List<List<T>> splitList(List<T> alist, int wantedParts) {
ArrayList<List<T>> result = new ArrayList<List<T>>();
int length = alist.length;
for (int i = 0; i < wantedParts; i++) {
result.append(alist.subList(i*length/wantedParts,
(i+1)*length/wantedParts));
}
return result;
}
If your alist will be structurally modified later in any way, you will have to make a copy of the sublist created by the subList method within the code, otherwise the results will be unpredictable.
Don't reinvent the wheel, the google collections api has a function called partition which does precisely that