How to determine current clipboard DataFlavor before get clip content - java

I have following trouble, when i copy Intellij Idea Editor text, and run
Toolkit.defaultToolkit.systemClipboard.getData(DataFlavor.stringFlavor)
it will raise:
Exception "java.lang.ClassNotFoundException: com/intellij/codeInsight/editorActions/FoldingData"while constructing DataFlavor for: application/x-java-jvm-local-objectref; class=com.intellij.codeInsight.editorActions.FoldingData
In fact, I hope ignore clip content with FoldingData, how to detect current clipboard DataFlavor

Clipboard data may be available in multiple flavors. Therefore, you should use Clipboard.getAvailableDataFlavors() and iterate through the array to determine if the DataFlavor you are looking for is there.
See http://docs.oracle.com/javase/7/docs/api/java/awt/datatransfer/Clipboard.html#getAvailableDataFlavors()
But if you are getting a ClassNotFoundException, this means that your runtime classpath is missing dependencies, so you need to fix this

This way you can check the DataFlavor earlier to avoid the UnsupportedFlavorException later
public class ClipBoard {
public static void main(String args[]) {
Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
try {
if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
String text = (String)t.getTransferData(DataFlavor.stringFlavor);
text=text.toUpperCase();
StringSelection ss = new StringSelection(text);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Read more: http://mrbool.com/manipulating-clipboard-content-with-java/24758#ixzz4tta4bwNQ

Related

How to properly close MappedByteBuffer?

This is the code I'm running:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class Main {
public static void main(String[] args) throws Exception {
String filePath = "D:/temp/file";
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
try {
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128);
// Do something
buffer.putInt(4);
} finally {
file.close();
System.out.println("File closed");
}
System.out.println("Press any key...");
System.in.read();
System.out.println("Finished");
}
}
Before pressing a key, I'm trying to delete the file manually in FAR Manager. But FAR says that the file is locked:
The process cannot access the file because it is being used by another process.
Cannot delete the file
D:\temp\file
Object is being opened in:
Java(TM) Platform SE binary (PID: 5768, C:\Program Files\Java\jdk1.8.0_05\bin\javaw.exe)
Only after pressing a key, the application terminates and I can delete the file.
What is wrong with my code?
Try this one.
public class Test
{
public static void main(String[] args) throws Exception {
String filePath = "D:/temp/file";
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
FileChannel chan = file.getChannel();
try {
MappedByteBuffer buffer = chan.map(FileChannel.MapMode.READ_WRITE, 0, 128);
// Do something
buffer.putInt(4);
buffer.force();
Cleaner cleaner = ((sun.nio.ch.DirectBuffer) buffer).cleaner();
if (cleaner != null) {
cleaner.clean();
}
} finally {
chan.close();
file.close();
System.out.println("File closed");
}
System.out.println("Press any key...");
System.in.read();
System.out.println("Finished");
}
}
#SANN3's answer doesn't work on Java 9 anymore. In Java 9 there is a new method sun.misc.Unsafe.invokeCleaner that can be used. Here is a working code:
MappedByteBuffer buffer = ...
// Java 9+ only:
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object unsafe = unsafeField.get(null);
Method invokeCleaner = unsafeClass.getMethod("invokeCleaner", ByteBuffer.class);
invokeCleaner.invoke(unsafe, buffer);
If you are using java1.8 and cannot directly use sun.nio.ch.DirectBuffer and Cleaner, you can try:
public void clean(final ByteBuffer buffer) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
try {
Field field = buffer.getClass().getDeclaredField("cleaner");
field.setAccessible(true);
Object cleaner = field.get(buffer);
Method cleanMethod = cleaner.getClass().getMethod("clean");
cleanMethod.invoke(cleaner);
} catch (Exception e) {
e.printStackTrace();
}
return null;
});
}
This is actually a limitation of JDK. Since the JDK-4724038 which tracks this problem (even though it is marked an enhancement) in JDK says that invoking the cleanup method directly is strongly advised against (also, that the Unsafe class might go away in some future version of JDK), the only workaround seems to be to call the GC. If using the try-with-resources for the file, that would look like this:
try (RandomAccessFile file = new RandomAccessFile(filePath, "rw")) {
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128);
// Do something
buffer.putInt(4);
}
System.gc(); // has to be called outside the try-with-resources block
I created https://github.com/vladak/RandomAccessFileTrap to demonstrate this - take a look at the detail of a build in the Github actions tab for this repository to see the actual results.

My custom "paste from clipboard" action

I want to find a way to do kind of a custom "paste from clipboard" action. Let's assume the content of clipboard is text for simplicity (not a file). Whenever you press Ctrl+V, it inserts that content (which is text) to a current open file which has a focus.
I have an app for catching a global hotkey. Note this is not a window application, it's a console one and it catches the hotkey globally. Let's say I have the hotkey of Ctrl+U. So what I want to do is when I press Ctrl+U I want to insert some predefined text to a current open file. Just like Ctrl+V does! The differences from a standard Ctrl+V is that I want to insert a predefined text and the hotkey is different.
How do I do this?
I'd prefer a cross-platform solution, however first of all I'm going to do that for Linux, specifically Ubuntu. The language is not important but Java or Scala would be better. Of course, I understand that the solutions is Java uses native OS' API for that.
I'm hoping that this hackish solution would work, but it is still untested, I am unsure how to catch the event for the hotkey.
The idea behind this code is the following five steps:
Get the old text in the clipboard and temporarily save it
Paste our predefined text into the clipboard
Trigger the global paste event
Release the global paste event
Reset the clipboard to the old text
This should give the appearance of a new clipboard (if not, hopefully it inspires you to come up with a better, less hackish solution).
Without further ado, here is my code. First I have a simple helper method to set the value of the clipboard (as we do this twice).
public static void setClipboard(String s) {
StringSelection contents = new StringSelection(s);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(contents, contents);
}
And then, I have a main method where I go through the five steps in order.
public static void main(String[] args) {
// Step 1 ) get old text
String oldText = "";
try {
oldText = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException ufe) {
ufe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Step 2 ) paste our text in clipboard
setClipboard("This lorem ipsum predefined string blows my mind.");
// Step 3 ) trigger paste event
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException awte) {
awte.printStackTrace();
}
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
// Step 4 ) Release paste event
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_V);
// Step 5 ) Reset clipboard
setClipboard(oldText);
}
[Edit]:
Here is some code to test what kind of contents are in the Clipboard - image, text, etc. The unicode error was coming from the fact that the old contents of the clipboard were something that couldn't be represented by a plain String. To fix this error, you will have to check if the old contents were an image, the old contents were text, and save them accordingly.
public static int kindOfContents() {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable contents = clipboard.getContents(null);
if(contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {
// String, save temporarily as string and write back as string
return 0;
} else if(contents.isDataFlavorSupported(DataFlavor.imageFlavor)) {
// Image, save temporarily as BufferedImage and write back as image
return 1;
} else if(contents.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
// List of files, save temporarily as java.util.List interface and write back as the file lists
return 2;
}
}
If the contents are text, then for saving and writing the content you would use the old method, repasted below for convenience.
// Step 1 ) get old text
String oldText = "";
try {
oldText = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException ufe) {
ufe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Step 5 ) Reset clipboard
setClipboard(oldText);
However, if the contents are an image, then for saving temporarily and rewriting you need to do the following. Note that the code for writing the image is not mine, but is taken from the accepted answer at Setting images to Clipboard - Java
// Step 1 ) get old image
BufferedImage img = null;
try {
img = (BufferedImage) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.imageFlavor);
} catch (UnsupportedFlavorException ufe) {
ufe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
Taken from Setting images to Clipboard - Java :
// Step 5 ) Reset clipboard
ImageTransferable transferable = new ImageTransferable( image );
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(transferable, null);
static class ImageTransferable implements Transferable
{
private Image image;
public ImageTransferable (Image image)
{
this.image = image;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException
{
if (isDataFlavorSupported(flavor))
{
return image;
}
else
{
throw new UnsupportedFlavorException(flavor);
}
}
public boolean isDataFlavorSupported (DataFlavor flavor)
{
return flavor == DataFlavor.imageFlavor;
}
public DataFlavor[] getTransferDataFlavors ()
{
return new DataFlavor[] { DataFlavor.imageFlavor };
}
}

Using the Default Editor Kit to put text on system clipboard

I have been trying for a month now to reliably set the system clipboard in my program. Currently it works about 95/100 times. But I keep searching.
Yesterday I came upon this the Java DefaultEditorKit.copyAction and died a little inside seeing there was already something written that might do what I want.
Though the problem is that this is a "Action" for a dialog?
How can I issue the text I want copied to the clipboard? I do not wish to attach this "Action" to any button/component in my app. I want to be able to do
DefaultEditorKit.copyAction("Put this on Clipboard");
But this is undefined. I am not sure how to trigger this "action" and give it some text to work with?
EDIT: Here is my code that causes an exception.
public void setClip2(String arg)
{
while(true)
{
try
{
sysClip.setContents(new StringSelection(arg), null);
}
catch(Exception e)
{
try {Thread.sleep(20);} catch (InterruptedException e1) {}
continue;
}
break;
}
return;
}
I just wondered if there was a way to reliably set the clipboard. (this method fails if you do not wait long enough trying to set it, which is usually about 1-2 seconds
Not sure why you have to wait to set the contents of the clipboard.
This program doesn't have any problem refreshing the clipboard every 200ms. That is the number increments by 1 every time is it displayed as expected:
import java.awt.*;
import java.awt.datatransfer.*;
import java.io.*;
class ClipboardLoopTest
{
public static void main(String[] args)
throws InterruptedException
{
for (int i = 0; i < 100; i++)
{
// add data to clipboard
try
{
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection testData;
testData = new StringSelection( "Test: " + i );
c.setContents(testData, testData);
// Get clipboard contents, as a String
Transferable t = c.getContents( null );
if ( t.isDataFlavorSupported(DataFlavor.stringFlavor) )
{
Object o = t.getTransferData( DataFlavor.stringFlavor );
String data = (String)t.getTransferData( DataFlavor.stringFlavor );
System.out.println( "Clipboard contents: " + data );
}
}
catch(Exception e)
{
System.out.println(e);
}
Thread.sleep(200);
}
System.exit(0);
}
}
I'm using JDK 7 on Windows 7.
Maybe you can post your SSCCE that demonstrates the problem.
DefaultEditorKit.copyAction actually use (through some layers) the functionnality in java.awt.datatransfer. There you will find classes to send data to the clipboard.
Basically, if you just want to send a string to the clipboard without using any Swing component, you setup a ClipboardOwner, you create a StringSelection object and you give it to the system clipboard. Here is a most basic example:
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents( new StringSelection("Put this on Clipboard"), new ClipboardOwner() {
#Override
public void lostOwnership(Clipboard clipboard, Transferable contents) {
System.out.println("I am no longer the clipboard owner.");
}
} );

How to paste from system clipboard content to an arbitrary window using Java

I would like to write a Java program that has a button. When the button is pressed it pastes / drops the content of the system clipboard to the text field that currently has focus within an arbitrary, possibly non-Java app (say MS Word). Essentially the button action has to simulate the sending of CTRL-V (paste) action somehow.
Does any one have any suggestions?
The package java.awt.datatransfer seems to be a solution, according to this article. Here is another article.
From the latter page, the needed imports:
import java.awt.datatransfer.*;
import java.awt.Toolkit;
And the method code is below. The solution is to create a listener and add it to the button. The listener should simply get the contents of the clipboard and insert it to whatever component you wish.
public void setClipboardContents( String aString ){
StringSelection stringSelection = new StringSelection( aString );
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents( stringSelection, this );
}
public String getClipboardContents() {
String result = "";
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
//odd: the Object param of getContents is not currently used
Transferable contents = clipboard.getContents(null);
boolean hasTransferableText =
(contents != null) &&
contents.isDataFlavorSupported(DataFlavor.stringFlavor)
;
if ( hasTransferableText ) {
try {
result = (String)contents.getTransferData(DataFlavor.stringFlavor);
}
catch (UnsupportedFlavorException ex){
//highly unlikely since we are using a standard DataFlavor
System.out.println(ex);
ex.printStackTrace();
}
catch (IOException ex) {
System.out.println(ex);
ex.printStackTrace();
}
}
return result;
}
Use the Actions provided by the editor kits:
JButton paste = new JButton( new DefaultEditorKit.PasteAction() );

ClassNotFoundException when deserializing a binary class file's contents

I don't know much about Java. I'm trying to read a file containing an int and various instances of a class called "Automobile". When I deserialize it, though, the program throws a ClassNotFoundException and I can't seem to understand why.
Here's the code:
try {
FileInputStream fin = new FileInputStream(inputFile);
ObjectInputStream input = new ObjectInputStream(fin);
conto = input.readInt();
Automobile[] macchine = new Automobile[conto];
for(int i = 0; i < conto; i++) {
macchine[i] = (Automobile)input.readObject();
}
String targa;
System.out.print("\nInserire le cifre di una targa per rintracciare l'automobile: ");
targa = sc1.nextLine();
for(int i = 0; i < conto; i++) {
if(macchine[i].getTarga().equals(targa))
System.out.println(macchine[i]);
}
} catch(IOException e) {
System.out.println("Errore nella lettura del file "+inputFile);
} catch(java.lang.ClassNotFoundException e) {
System.out.println("Class not found");
}
Thanks in advance.
EDIT: here's the stacktrace
java.lang.ClassNotFoundException: es4.Automobile
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:604)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1575)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at es4p2.Main.main(Main.java:35)
When you deserialize a serialized object tree, the classes of all the objects have to be on the classpath. In this context, a ClassNotFoundException most likely means that one of the classes required is not on the classpath. You have to address this for deserialization to work.
In this case, the es4.Automobile is missing.
Could the problem be caused by a custom exception I made which is fired by Automobile?
The only other possibilities I can think of are:
es4.Automobile has a direct or indirect dependency on some other class that is missing
the static initialization of es4.Automobile or a dependent class has thrown an exception that has not been caught internally to the class.
But both of those should (I think) have resulted in a different stack trace.
I just noticed the package name is es4p2, not es4. Why does it say es4? Could it be because the program which saves the file uses another package name?
I've no idea why they are different. You'd need to talk to whoever wrote the code / produced the serialized objects. However, this is most likely the cause of your problem. A class with a different package name is a different class. Period.
You should always output (or better, log) the stacktrace when an unexpected exception is caught. That will tell you (and us) more about what has gone wrong, and in this case the name of the class that is missing.
This is and old question but this may help someone else. I faced the same issue and the problem was that I was not using the current thread class loader. You will find below the serializer class that I used in a grails project, should be quite straightforward use this in java
Hope this helps
public final class Serializer<T> {
/**
* Converts an Object to a byte array.
*
* #param object, the Object to serialize.
* #return, the byte array that stores the serialized object.
*/
public static byte[] serialize(T object) {
ByteArrayOutputStream bos = new ByteArrayOutputStream()
ObjectOutput out = null
try {
out = new ObjectOutputStream(bos)
out.writeObject(object)
byte[] byteArray = bos.toByteArray()
return byteArray
} catch (IOException e) {
e.printStackTrace()
return null
} finally {
try {
if (out != null)
out.close()
} catch (IOException ex) {
ex.printStackTrace()
return null
}
try {
bos.close()
} catch (IOException ex) {
ex.printStackTrace()
return null
}
}
}
/**
* Converts a byte array to an Object.
*
* #param byteArray, a byte array that represents a serialized Object.
* #return, an instance of the Object class.
*/
public static Object deserialize(byte[] byteArray) {
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray)
ObjectInput input = null
try {
input = new ObjectInputStream(bis){
#Override protected Class<?> resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) return super.resolveClass(desc);
return Class.forName(desc.getName(), false, cl);
}
};
Object o = input.readObject()
return o
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace()
return null
} finally {
try {
bis.close()
} catch (IOException ex) {
}
try {
if (input != null)
input.close()
} catch (IOException ex) {
ex.printStackTrace()
return null
}
}
}
This generally happens if your class Automobile is not in the runtime classpath.
I fixed it in an easier way than the other answers -- my problem occurred when using the class in multiple projects.
If you have multiple projects, make sure that the specific class you're deserializing is in the exact same path! That means, the same package names etc inside that project. Otherwise it won't find it and cause the ClassNotFoundException to be thrown.
So if it's in
/myPackage/otherPackage/Test.java
Then make sure, that path is exactly the same in your other project.
Ive had a similar problem with a ObjectInputStream reading serialized Objects. The classes for those Objects i added at runtime with a URLClassloader. The problem was that the ObjectInputStream did not use the Thread ClassLoader which i set with
Thread.currentThread().setContextClassLoader(cl);
but instead the AppClassLoader, which you cannot customize with java 9. So i made my own ObjectInputStream as a subtype of the original one and overidden the resolveClass Method:
#Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String name = desc.getName();
try {
return Class.forName(name, false, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException ex) {
Class<?> cl = primClasses.get(name);
if (cl != null) {
return cl;
} else {
throw ex;
}
}
}
Does your Automobile class have a field like this?
private static final long serialVersionUID = 140605814607823206L; // some unique number
If not, define one. Let us know if that fixes it.
You can access the class name from the message of the ClassNotFound exception - it's horrible to depend on this in the code - but it should give you some idea. I wish there were some better way of getting information about serialised objects without having to have the class available.

Categories