Simplest way to make custom debug watch in Eclipse? - java

Is it possible to create custom variable viewers in Eclipse? Suppose I wish to decompose bitfield or see bitmap as an image. Is it possible?
Can you give some simplest example?
UPDATE
I have tried to implement the following example: http://alvinalexander.com/java/jwarehouse/eclipse/org.eclipse.jdt.debug.tests/test-plugin/org/eclipse/jdt/debug/testplugin/detailpane/SimpleDetailPane.java.shtml
My plugin.xml is follows:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
<extension
point="org.eclipse.debug.ui.detailPaneFactories">
<detailFactories
class="tests.debug.details.DetailPaneFactory"
id="tests.debug.details.detailFactories">
</detailFactories>
</extension>
</plugin>
My DetailPaneFactory.java is follows:
package tests.debug.details;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.debug.ui.IDetailPane;
import org.eclipse.debug.ui.IDetailPaneFactory;
import org.eclipse.jface.viewers.IStructuredSelection;
public class DetailPaneFactory implements IDetailPaneFactory {
private HashMap<String,Class<? extends IDetailPane>> classes = new HashMap<String,Class<? extends IDetailPane>>();
private void addClass(Class<? extends IDetailPane> cls) {
try {
String paneID = (String) cls.getField("ID").get(null);
classes.put(paneID, cls);
} catch (IllegalArgumentException | IllegalAccessException
| NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
finally {
}
}
private Class<? extends IDetailPane> getClass(String paneID) {
Class<? extends IDetailPane> ans = classes.get(paneID);
return ans;
}
public DetailPaneFactory() {
addClass(SimpleDetailPane.class);
}
#Override
public IDetailPane createDetailPane(String paneID) {
Class<? extends IDetailPane> cls = getClass(paneID);
if( cls != null ) {
try {
return cls.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException();
}
}
else {
return null;
}
}
#Override
public String getDetailPaneName(String paneID) {
Class<? extends IDetailPane> cls = getClass(paneID);
if( cls != null ) {
try {
return (String)cls.getField("NAME").get(null);
} catch (IllegalArgumentException | IllegalAccessException
| NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
else {
return null;
}
}
#Override
public String getDetailPaneDescription(String paneID) {
Class<? extends IDetailPane> cls = getClass(paneID);
if( cls != null ) {
try {
return (String)cls.getField("DESCRIPTION").get(null);
} catch (IllegalArgumentException | IllegalAccessException
| NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
else {
return null;
}
}
#Override
public Set<String> getDetailPaneTypes(IStructuredSelection selection) {
return new AbstractSet<String>() {
#Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private Iterator<Map.Entry<String,Class<? extends IDetailPane>>> it = classes.entrySet().iterator();
#Override
public void remove() {
it.remove();
}
#Override
public String next() {
return it.next().getKey();
}
#Override
public boolean hasNext() {
return it.hasNext();
}
};
}
#Override
public int size() {
return classes.size();
}
};
}
#Override
public String getDefaultDetailPane(IStructuredSelection selection) {
return SimpleDetailPane.ID;
}
}
and my SimpleDetailPane.java is as in example.
And it apparently works.

You can use Window / Show View / Expressions and add your expression that could make some calculations and show a textual output. But in order to anything else than a text output you'll have to contribute your own model presentation trough Eclipse platform extension points. See Detail Pane Factories Extension and source of org.eclipse.temp.JavaTableDetailPaneFactory class in Eclipse's own JDT.
As a quick workaround you can also write a static utility method that will open a new window with your image converted from a bitfield and call that method from a Display view using Ctrl-U shortcut.

Related

Using reflection to identify if the error thrown matches expected error

I need to write a simple code tester program, but I got stuck comparing the given error class with the test expected class. I am supposed to use reflection in this exercise.
I have my code testing class:
public class TestRunner {
private String result = "";
public void runTests(List<String> testClassNames) {
for (String testClassName : testClassNames) {
Class<?> clazz;
try {
clazz = Class.forName(testClassName);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("No such class.");
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getAnnotation(MyTest.class) != null) {
if (testClassName.equals("reflection.tester.ExampleTests1")) {
result += method.getName() + "() - ";
ExampleTests1 instance = new ExampleTests1();
try {
// if null, result = OK
method.invoke(instance);
result += "OK\n";
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
// if error is caught result = FAILED
result += "FAILED\n";
}
} else {
// the second class. should only return "OK" if the error is implemented from the exception class
result += method.getName() + "() - ";
ExampleTests2 instance = new ExampleTests2();
try {
method.invoke(instance);
result += "FAILED\n";
} catch (RuntimeException e) {
Throwable original = e.getCause();
Object expected = method.getReturnType();
if (original.getClass().isAssignableFrom(expected.getClass())) {
result += "OK\n";
} else {
result += "FAILED\n";
}
} catch (InvocationTargetException | IllegalAccessException e) {
result += "ERROR\n";
}
}
}
}
}
}
}
Also have two test classes. In the first one there is only one rule, if the test won't throw an exception the test should pass, and it is working. The second class is more complicated. If the thrown error class is implemented or same to the expected error class then the test should pass and OK should be added to the result. Currently my code won't catch RunTimeException at all and moves to the last catch block. How can I fix this?
I will also add the test class for more information.
public class ExampleTests2 {
#MyTest(expected = RuntimeException.class)
public void test3() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test4() {
throw new RuntimeException();
}
#MyTest(expected = IllegalStateException.class)
public void test5() {
throw new IllegalStateException();
}
#MyTest(expected = IllegalStateException.class)
public void test6() {
}
public void helperMethod() {
}
}
test3() and test5() should pass, test4() and test6() should fail, helperMethod() won't be checked because I only need to use the tests with #MyTest annotation.
JUnit has an assertThrows method that checks that an Exception is thrown. It has a method signature of
static <T extends Throwable> assertThrows​(Class<T> expectedType, Executable executable){}
Here's the documentation: https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html#assertThrows(java.lang.Class,org.junit.jupiter.api.function.Executable)
and here's how JUnit implements it:
https://github.com/junit-team/junit5/blob/main/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AssertThrows.java

Returning Unknown Type Java

So I'm working with JSON in Java and JSON can have a base of either an Array or an Object. In my Config class, I take a class as an argument so I can create the file accordingly if it doesn't exist. I also store the class as a private field so I know in future.
However, when I get to reading the file, I'd prefer to have multiple return types though the same method name. If I return Object, I then have to cast the returned value which I want to avoid.
Current code:
public class Config {
private File dir = null;
private File file = null;
private Class clazz = null;
public Config(String program, String fileName, Class root) throws IOException {
this.dir = new File(System.getProperty("user.home") + File.separator + program);
if (!this.dir.exists()) {
this.dir.mkdir();
}
this.file = new File(this.dir + File.separator + fileName);
if (!this.file.exists()) {
this.file.createNewFile();
if (root.getName().equals(JSONArray.class.getName())) {
Files.write(this.file.toPath(), "[]".getBytes());
} else if (root.getName().equals(JSONObject.class.getName())) {
Files.write(this.file.toPath(), "{}".getBytes());
}
}
this.clazz = root;
}
public JSONArray readConfig() {
return null;
}
public JSONObject readConfig() {
return null;
}
}
Is there anyway I can do what I want without having to return Object?
multiple return types though the same method name
well, it is possible to use generic function to achieve that. For example,
public static void main(String[] args) {
try {
String t = getObject(String.class);
Integer d = getObject(Integer.class);
} catch (Exception e) {
e.printStackTrace();
}
}
public static <T> T getObject(Class<T> returnType) throws Exception {
if(returnType == String.class) {
return (T) "test";
} else if(returnType == Integer.class) {
return (T) new Integer(0);
} else {
return (T) returnType.newInstance();
}
}
Will the following code even compile?
I'm afraid no. There are few compilation errors such as
public Object readConfig() {
try {
// Assume jsonString exists
return (this.clazz.getDeclaredConstructor(String.class).newInstance(jsonString)); <--- clazz should be getClass()
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
<---- missing return statement
}
}

ClassCastException when casting Class.forName object to interface implemented by this object

I want to create some plugin example for android, so I have 3 projects for it:
ExternalLibInterface - contains IExternalLib, and builds to externallibinterface.jar file
package com.example.externallibinterface;
public interface IExternalLib {
public String someMethod( String param );
}
ExternalLib - contains externallibinterface.jar and SomeClass implements IExternalLib, builds to externallib.apk
package com.example.externallib;
import com.example.externallibinterface.IExternalLib;
public class SomeClass implements IExternalLib {
public String someMethod(String arg0) {
return arg0;
}
}
SomeApp - contains externallibinterface.jar and class for activity - application where I load external apk and class from it.
import com.example.externallibinterface.IExternalLib;
import dalvik.system.PathClassLoader;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String apkToLoad = null;
String externalPackagePath = "com.example.externallib";
String externalClassPath = "com.example.externallib.SomeClass";
try {
apkToLoad = getPackageManager()
.getApplicationInfo( externalPackagePath, MODE_PRIVATE ).sourceDir;
} catch ( PackageManager.NameNotFoundException e ) {
e.printStackTrace();
}
PathClassLoader pathClassLoader =
new PathClassLoader( apkToLoad,
ClassLoader.getSystemClassLoader() );
try {
Class<?> c = Class.forName( externalClassPath, true, pathClassLoader );
Object someClassInstance = c.newInstance();
//exception ClassCastException here
IExternalLib i = (IExternalLib) someClassInstance;
i.someMethod( "some string" );
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch ( ClassCastException e ) {
e.printStackTrace();
}
}
}
But when I cast Object someClassInstance to IExternalLib I get ClassCastException.
Why? IExternalLib is defined in 3rd place (in externallibinterface.jar).
Try the following:
Class<? extends IExternalLib> l_clazz; // our expected class
Class<?> clazz = Class.forName("com.example.externallib.SomeClass"); // our unknown class
// check if our unknown class can be cast to our expected class
if ((l_clazz = clazz.asSubclass(IExternalLib.class)) != null) {
IExternalLib i = l_clazz.newInstance();
i.someMethod( "some string" );
}
It could happen when different class loaders are loading the class. Make sure to build the whole setup at once so that only one class loader is responsible for loading the classes. It happens frequently when you are just re-deploying a particular .war file onto a existing system. Please see this for more insight can't cast to implemented interface

Not the same object after a deserialization in a data transfer

I really need some help down here...
I'm working on drag and drop event in a Jtree.
I've created a TransferHandler to manage the drag and drop.
Source : KineticsTransferHandler.java
package tree;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.TreePath;
import datastructures.base.Acquisition;
import datastructures.base.Kinetics;
import datastructures.base.Location;
public class KineticsTransferHandler extends TransferHandler{
private static final long serialVersionUID = -5653477841078614666L;
final public static DataFlavor ACQUISITION_NODE = new DataFlavor(Acquisition.class, "Acquisition Node");
static DataFlavor flavors[] = { ACQUISITION_NODE };
#Override
public int getSourceActions(JComponent c) {
return MOVE;
}
#Override
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
TreePath path = tree.getSelectionPath();
System.out.println(tree.getSelectionPath().toString());
if (path != null) {
Object o = path.getLastPathComponent();
if(o instanceof Acquisition) {
return new AcquisitionTransferable((Acquisition)o);
}
}
return null;
}
#Override
protected void exportDone(JComponent source, Transferable data, int action) {
if(action != NONE) {
JTree tree = (JTree) source;
StudyTreeModel model = (StudyTreeModel)tree.getModel();
model.printStudy();
tree.updateUI();
}
}
#Override
public boolean canImport(TransferHandler.TransferSupport support) {
boolean canImport = false;
if (support.isDrop()) {
Acquisition source = null;
if (support.isDataFlavorSupported(ACQUISITION_NODE)) {
try {
source = (Acquisition) support.getTransferable().getTransferData(ACQUISITION_NODE);
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(source != null) {
JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation();
Object dest = dropLocation.getPath().getLastPathComponent();
canImport = sameLocation(source, dest);
}
}
}
return canImport;
}
/*Verifies that the source and the dest are in the same Location*/
private boolean sameLocation(Acquisition source, Object dest) {
/*...
A method to check if the source has the same Location than the dest.
...*/
}
#Override
public boolean importData(TransferHandler.TransferSupport support) {
boolean importData = false;
if (canImport(support)) {
Acquisition source = null;
if (support.isDataFlavorSupported(ACQUISITION_NODE)) {
try {
source = (Acquisition) support.getTransferable().getTransferData(ACQUISITION_NODE);
((StudyTree)support.getComponent()).gettr
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation)support.getDropLocation();
Object dest = dropLocation.getPath().getLastPathComponent();
int childIndex = dropLocation.getChildIndex();
if (sameLocation(source, dest)) {// dest and source get the same Location
/*...
Management of the drop according to the dest.
...*/
}
}
return importData;
}
public class AcquisitionTransferable implements Transferable {
Acquisition acquisition;
public AcquisitionTransferable(Acquisition s) {
acquisition = s;
}
#Override
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException {
if (!isDataFlavorSupported(flavor))
throw new UnsupportedFlavorException(flavor);
return acquisition;
}
#Override
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
#Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return ACQUISITION_NODE.equals(flavor);
}
}
}
It uses an Transferable for the data transfert that I've called AcquisitionTransferable (as you can see in the end).
My problem(s) came(s) from this part
Source : KineticsTransferHandler.canImport(TransferHandler.TransferSupport)
source = (Acquisition) support.getTransferable().getTransferData(ACQUISITION_NODE);
The structure that I've, in the end, in source(the one above) is like a copy of the real one. When I'm debugging, I can see that the source's ID is not the same as in the real one.
But in support(parameter of KineticsTransferHandler.canImport(TransferHandler.TransferSupport)), I've my Jtree which contains the structure, wich is the good one.
So, what I'm thinking is, there is a problem in the access of the structure in getTransferData, it may be a problem with the serialization. When I access my structure, getTransferData deserializes the structure and this is why I get like a clone of it.
Do you have any idea of how I should fix it?
You need to define your DataFlavor with a javaJVMLocalObjectMimeType, to signify that the transferred data resides in the local JVM. In your case, the DataFlavor definition should look like:
final public static DataFlavor ACQUISITION_NODE =
new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType+"; class=\"" +Acquisition.class.getCanonicalName()+"\""
,"Acquisition Node");
Check the other two Java object MIME types here also.

What is the best way to write to a file in a parallel thread in Java?

I have a program that performs lots of calculations and reports them to a file frequently. I know that frequent write operations can slow a program down a lot, so to avoid it I'd like to have a second thread dedicated to the writing operations.
Right now I'm doing it with this class I wrote (the impatient can skip to the end of the question):
public class ParallelWriter implements Runnable {
private File file;
private BlockingQueue<Item> q;
private int indentation;
public ParallelWriter( File f ){
file = f;
q = new LinkedBlockingQueue<Item>();
indentation = 0;
}
public ParallelWriter append( CharSequence str ){
try {
CharSeqItem item = new CharSeqItem();
item.content = str;
item.type = ItemType.CHARSEQ;
q.put(item);
return this;
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public ParallelWriter newLine(){
try {
Item item = new Item();
item.type = ItemType.NEWLINE;
q.put(item);
return this;
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public void setIndent(int indentation) {
try{
IndentCommand item = new IndentCommand();
item.type = ItemType.INDENT;
item.indent = indentation;
q.put(item);
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public void end(){
try {
Item item = new Item();
item.type = ItemType.POISON;
q.put(item);
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public void run() {
BufferedWriter out = null;
Item item = null;
try{
out = new BufferedWriter( new FileWriter( file ) );
while( (item = q.take()).type != ItemType.POISON ){
switch( item.type ){
case NEWLINE:
out.newLine();
for( int i = 0; i < indentation; i++ )
out.append(" ");
break;
case INDENT:
indentation = ((IndentCommand)item).indent;
break;
case CHARSEQ:
out.append( ((CharSeqItem)item).content );
}
}
} catch (InterruptedException ex){
throw new RuntimeException( ex );
} catch (IOException ex) {
throw new RuntimeException( ex );
} finally {
if( out != null ) try {
out.close();
} catch (IOException ex) {
throw new RuntimeException( ex );
}
}
}
private enum ItemType {
CHARSEQ, NEWLINE, INDENT, POISON;
}
private static class Item {
ItemType type;
}
private static class CharSeqItem extends Item {
CharSequence content;
}
private static class IndentCommand extends Item {
int indent;
}
}
And then I use it by doing:
ParallelWriter w = new ParallelWriter( myFile );
new Thread(w).start();
/// Lots of
w.append(" things ").newLine();
w.setIndent(2);
w.newLine().append(" more things ");
/// and finally
w.end();
While this works perfectly well, I'm wondering:
Is there a better way to accomplish this?
Your basic approach looks fine. I would structure the code as follows:
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public interface FileWriter {
FileWriter append(CharSequence seq);
FileWriter indent(int indent);
void close();
}
class AsyncFileWriter implements FileWriter, Runnable {
private final File file;
private final Writer out;
private final BlockingQueue<Item> queue = new LinkedBlockingQueue<Item>();
private volatile boolean started = false;
private volatile boolean stopped = false;
public AsyncFileWriter(File file) throws IOException {
this.file = file;
this.out = new BufferedWriter(new java.io.FileWriter(file));
}
public FileWriter append(CharSequence seq) {
if (!started) {
throw new IllegalStateException("open() call expected before append()");
}
try {
queue.put(new CharSeqItem(seq));
} catch (InterruptedException ignored) {
}
return this;
}
public FileWriter indent(int indent) {
if (!started) {
throw new IllegalStateException("open() call expected before append()");
}
try {
queue.put(new IndentItem(indent));
} catch (InterruptedException ignored) {
}
return this;
}
public void open() {
this.started = true;
new Thread(this).start();
}
public void run() {
while (!stopped) {
try {
Item item = queue.poll(100, TimeUnit.MICROSECONDS);
if (item != null) {
try {
item.write(out);
} catch (IOException logme) {
}
}
} catch (InterruptedException e) {
}
}
try {
out.close();
} catch (IOException ignore) {
}
}
public void close() {
this.stopped = true;
}
private static interface Item {
void write(Writer out) throws IOException;
}
private static class CharSeqItem implements Item {
private final CharSequence sequence;
public CharSeqItem(CharSequence sequence) {
this.sequence = sequence;
}
public void write(Writer out) throws IOException {
out.append(sequence);
}
}
private static class IndentItem implements Item {
private final int indent;
public IndentItem(int indent) {
this.indent = indent;
}
public void write(Writer out) throws IOException {
for (int i = 0; i < indent; i++) {
out.append(" ");
}
}
}
}
If you do not want to write in a separate thread (maybe in a test?), you can have an implementation of FileWriter which calls append on the Writer in the caller thread.
One good way to exchange data with a single consumer thread is to use an Exchanger.
You could use a StringBuilder or ByteBuffer as the buffer to exchange with the background thread. The latency incurred can be around 1 micro-second, doesn't involve creating any objects and which is lower using a BlockingQueue.
From the example which I think is worth repeating here.
class FillAndEmpty {
Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
DataBuffer initialEmptyBuffer = ... a made-up type
DataBuffer initialFullBuffer = ...
class FillingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialEmptyBuffer;
try {
while (currentBuffer != null) {
addToBuffer(currentBuffer);
if (currentBuffer.isFull())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ... }
}
}
class EmptyingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialFullBuffer;
try {
while (currentBuffer != null) {
takeFromBuffer(currentBuffer);
if (currentBuffer.isEmpty())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ...}
}
}
void start() {
new Thread(new FillingLoop()).start();
new Thread(new EmptyingLoop()).start();
}
}
Using a LinkedBlockingQueue is a pretty good idea. Not sure I like some of the style of the code... but the principle seems sound.
I would maybe add a capacity to the LinkedBlockingQueue equal to a certain % of your total memory.. say 10,000 items.. this way if your writing is going too slow, your worker threads won't keep adding more work until the heap is blown.
I know that frequent write operations
can slow a program down a lot
Probably not as much as you think, provided you use buffering.

Categories