Java Swing is rather complex. You can do just about anything, but it can be hard to know how to do it. I have for a long time tried to adapt the visible (preferred) size of a JTable. I know how many rows I would like to display, but it is hard to know how to write the code for it.
I figured out this code today:
package se.lesc.blog;
import java.awt.Insets;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import static javax.swing.GroupLayout.DEFAULT_SIZE;
public class TableRowDemo extends JFrame {
Object[][] data = { {"Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false)},
{"John", "Doe", "Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black", "Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White", "Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown", "Pool", new Integer(10), new Boolean(false)}
};
String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"};
public static void main(String [] args) {
new TableRowDemo().setVisible(true);
}
public TableRowDemo() {
GroupLayout layout = new GroupLayout(getContentPane());
JLabel label = new JLabel("My table:");
JTable table = new JTable(data, columnNames);
JScrollPane tableScrollPane = new JScrollPane(table);
int numberOfRowsToDisplay = 3;
//Fetch the border "padding"
Insets insets = tableScrollPane.getBorder().getBorderInsets(table);
//Compute the total height of the table
int preferredTableHeight = insets.bottom + insets.top
+ (int) table.getTableHeader().getPreferredSize().getHeight() +
numberOfRowsToDisplay * table.getRowHeight();
layout.setVerticalGroup(layout.createSequentialGroup()
.addComponent(label)
.addComponent(tableScrollPane, DEFAULT_SIZE, preferredTableHeight, DEFAULT_SIZE)
);
layout.setHorizontalGroup(layout.createParallelGroup()
.addComponent(label)
.addComponent(tableScrollPane)
);
getContentPane().setLayout(layout);
pack();
}
}
29 October 2015
15 September 2015
How Microsoft SmartScreen works and how it stores data in NTFS streams
Windows 10
(and 8) has a feature called Microsoft SmartScreen. It is split in two parts:
one purely for the web and one for files downloaded for the web. I’ll try to
explain how SmartScreen for downloaded files work. But first we need to know how
streams works
ADS or just
”streams” is a feature in Microsoft NTFS file system feature that allows for ”hidden”
data in a file. You can access the hidden data by using the colon separator.
Copy
ftp.exe from C:\Windows\System32 to c:\temp\. I used ftp.exe because it is an
unsigned executable that you probably can find on your hard drive. Use Windows
PowerShell for these commands. Create an alternative stream by using notepad:
PS
C:\temp> notepad ftp.exe:LennartStream
Answer yes
in Notepad. Enter the content ”Hello World!”, save and close the file/stream.
We can now open the file/stream by the same Notepad command again. No actual new
file was created on the hard drive. It just created a new stream. You can
list the streams by using Windows Sysinternals Streams program or just use
PowerShell:
PS C:\temp> Get-Item ftp.exe -Stream *FileName: C:\temp\ftp.exe
Stream Length
------ ------
:$DATA 55808
LennartStream.txt 12
As you can
see my ”LennartStream” is there and it takes 12 bytes (the ”Hello World!”
string). The main program for ftp takes 55808 bytes.
Microsoft SmartScreen
SmartScreen
(https://en.wikipedia.org/wiki/Microsoft_SmartScreen) provides some protection for
executing downloaded files from the internet. When a file is downloaded in the web browser
(for example Firefox), a stream called “Zone.Identifier” is created. If the
Zone is “dangerous” a warning dialog may be presented to the user when the file
is run. In Windows 10 the settings for SmartScreen is in Control Panel\System
and Security\Security and Maintenance.
Use notepad
to edit the Zone.Identifier stream:
PS
C:\temp> notepad ftp.exe:Zone.Identifier
Create a
new stream and enter this content:
[ZoneTransfer]
ZoneId=3
Now double click
on ftp.exe to run it. You will now get a dialog like this:
“Windows
protected your PC. Windows SmartScreen prevented an unrecognized app from
starting. Running this app might put your PC at risk”
Press “More
info”:
Choose “Run
anyway” and then just close the ftp program. View the Zone.Identifier stream
again:
PS
C:\temp> notepad ftp.exe:Zone.Identifier
The content
has now changed to:
[ZoneTransfer]
AppZoneId=4
As you can
see SmartScreen has updated the stream data with respect to your answer in the
dialog.
Please note
that if the file is signed with a certificate and Microsoft can verify it (with
some magical “reputation” system I don’t know the details on) the dialog may
not be shown and the stream will not be changed.
23 April 2014
What to do when you get "Comparison method violates its general contract!"
Java 7 switched to a new sort algorithm - called ComparableTimSort. The old algorithm would silently ignore when you violate the Comparator/Comparable contract. The new one throws an exception "Comparison method violates its general contract!"
The contract is in the interface Comparable. The most common is to break the transitive contract. That is: If A < B and B < C, than A should be less than C. Stackoverflow.com has several posts on the issue.
I have made a small program that detects what elements that causes this issue. It only works for small lists but has helped me to debug compareTo()/compare() methods.
Here is some test code for the above class:
The contract is in the interface Comparable. The most common is to break the transitive contract. That is: If A < B and B < C, than A should be less than C. Stackoverflow.com has several posts on the issue.
I have made a small program that detects what elements that causes this issue. It only works for small lists but has helped me to debug compareTo()/compare() methods.
package se.lesc.blog;
import java.util.Comparator;
public class TransitivityTester {
public static void transitivityTester(Object list[]) {
transitivityTester(list, null);
}
/** Check that a lists compareTo() method is correct with respect to transitivity */
public static void transitivityTester(Object list[], Comparator<Object> comparator) {
//Cache all possible comparison (for speed)
byte[][] compareTable = new byte[list.length][];
for (int x = 0; x < list.length; x++) {
byte[] column = new byte[list.length];
compareTable[x] = column;
for (int y = 0; y < list.length; y++) {
int result;
if (comparator != null) {
result = comparator.compare(list[x], list[y]);
} else {
@SuppressWarnings("unchecked")
Comparable<Object> comparableX = (Comparable<Object>)list[x];
result = comparableX.compareTo(list[y]);
}
byte normalizedResult = normalize(result);
column[y] = normalizedResult;
}
}
//Expensive O(n^3) iteration
for (int a = 0; a < list.length; a++) {
for (int b = 0; b < list.length; b++) {
for (int c = 0; c < list.length; c++) {
if (compareTable[a][b] < 0 && compareTable[b][c] < 0) {
if (! (compareTable[a][c] < 0)) {
transitiveError("A < B && B < C but not A < C", a, b, c);
}
} else if (compareTable[a][b] > 0 && compareTable[b][c] > 0) {
if (! (compareTable[a][c] > 0)) {
transitiveError("A > B && B > C but not A > C", a, b, c);
}
} else if (compareTable[a][b] == 0 && compareTable[b][c] == 0) {
if (! (compareTable[a][c] == 0)) {
transitiveError("A == B && B == C but not A == C", a, b, c);
}
}
}
}
}
}
private static void transitiveError(String transitiveRule, int a, int b, int c) {
String errorMessage =
transitiveRule +
" (A = " + a + ", B= " + b + ", C = " + c + ") " +
"Comparison method violates its general contract!";
throw new IllegalArgumentException(errorMessage);
}
private static byte normalize(int result) {
byte normalizedResult;
if (result > 0) {
normalizedResult = 1;
} else if (result < 0) {
normalizedResult = -1;
} else {
normalizedResult = 0;
}
return normalizedResult;
}
}
Here is some test code for the above class:
package se.lesc.blog;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
public class TransitivityTesterTest {
private List<Integer> list;
@Before
public void setUp() {
list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
}
@Test
public void testNormalIntegerListShouldWork() {
TransitivityTester.transitivityTester(list.toArray(new Integer[0]));
}
@Test
public void testCrazyOneIsAlwaysMoreComparator() {
TransitivityTester.transitivityTester(list.toArray(new Integer[0]), new CrazyOneIsAlwaysMoreComparator());
}
@Test
public void testCrazyAllIsOneComparator() {
TransitivityTester.transitivityTester(list.toArray(new Integer[0]), new CrazyAllIsOneComparator());
}
public static class CrazyOneIsAlwaysMoreComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
if (i1.intValue() == 1) {
return 1;
} else {
return i1.compareTo(i2);
}
}
}
public static class CrazyAllIsOneComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
if (i1.intValue() == 1 || i2.intValue() == 1) {
return 0;
} else {
return i1.compareTo(i2);
}
}
}
}
15 January 2014
More Btrace debugging
In the post http://blog.lesc.se/2009/06/btrace-debugging-tool-with-bugs.html I wrote about how it is possible to debug a running Java application. Here is some more magic.
Let say you have this simple program:
import javax.swing.JFrame;
public class SimpleApp {
public static void main(String args[]) {
JFrame frame = new JFrame("Simple application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 100);
frame.setVisible(true);
}
}
And this Btrace script:
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import java.awt.EventQueue;
import java.awt.AWTEvent;
import java.awt.event.MouseEvent;
import java.lang.reflect.Field;
@BTrace
public class SimpleAppMouseTracer {
@OnMethod(
clazz="java.awt.EventQueue",
method="dispatchEvent"
)
public static void onevent(@Self EventQueue queue, AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
Field idField = field("java.awt.AWTEvent", "id");
Field xField = field("java.awt.event.MouseEvent", "x");
Field yField = field("java.awt.event.MouseEvent", "y");
if (getInt(idField, mouseEvent) == MouseEvent.MOUSE_CLICKED) {
println(
strcat("x = ", strcat(str(getInt(xField, mouseEvent)),
strcat(", y = ", str(getInt(yField, mouseEvent))))));
}
}
}
}
I have installed the Btrace into Java VisualVM (I downloaded and installed all the visualvm plugins from https://kenai.com/projects/btrace/downloads).
Each time I click with the mouse inside the Window I get a printout with the mouse coordinates.
The Btrace code is Java, but with many restrictions. That is why the String creation code gets a bit large; because build in Btrace functions must be used. The same goes for accessing variables inside the MouseEvent object.
Let say you have this simple program:
import javax.swing.JFrame;
public class SimpleApp {
public static void main(String args[]) {
JFrame frame = new JFrame("Simple application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 100);
frame.setVisible(true);
}
}
And this Btrace script:
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import java.awt.EventQueue;
import java.awt.AWTEvent;
import java.awt.event.MouseEvent;
import java.lang.reflect.Field;
@BTrace
public class SimpleAppMouseTracer {
@OnMethod(
clazz="java.awt.EventQueue",
method="dispatchEvent"
)
public static void onevent(@Self EventQueue queue, AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
Field idField = field("java.awt.AWTEvent", "id");
Field xField = field("java.awt.event.MouseEvent", "x");
Field yField = field("java.awt.event.MouseEvent", "y");
if (getInt(idField, mouseEvent) == MouseEvent.MOUSE_CLICKED) {
println(
strcat("x = ", strcat(str(getInt(xField, mouseEvent)),
strcat(", y = ", str(getInt(yField, mouseEvent))))));
}
}
}
}
I have installed the Btrace into Java VisualVM (I downloaded and installed all the visualvm plugins from https://kenai.com/projects/btrace/downloads).
Each time I click with the mouse inside the Window I get a printout with the mouse coordinates.
The Btrace code is Java, but with many restrictions. That is why the String creation code gets a bit large; because build in Btrace functions must be used. The same goes for accessing variables inside the MouseEvent object.
08 August 2013
A Java program that triggers the java.lang.OutOfMemoryError: GC overhead limit exceeded
I wanted to test how the -XX:+HeapDumpOnOutOfMemoryError JVM option worked when a JVM goes out of memory, but because of GC overheadlimit. This is my try:
This works very nice. You have to modify the MEMORY_BLOCK_MAX_SIZE and REMOVE_BLOCK_FACTOR to match your memory settings. I used a 8 GB heap for my numbers.
Nice things to note:
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class OutOfMemoryProvoker {
private static final int MEMORY_BLOCK_MAX_SIZE = 1000000;
private static final int REMOVE_BLOCK_FACTOR = 20000;
public static void main(String[] args) throws Exception {
final ArrayList<byte[]> list = new ArrayList<byte[]>();
Random random = new Random(0);
Timer timer = new Timer("reportTimer");
timer.schedule(new TimerTask() {
@Override
public void run() {
report(list);
}
}, 5000, 5000);
while (true) {
int memSize = random.nextInt(MEMORY_BLOCK_MAX_SIZE) + 1;
byte[] memBlock = new byte[memSize];
list.add(memBlock);
int removeBlockIndex = random.nextInt(REMOVE_BLOCK_FACTOR);
if (list.size() > removeBlockIndex) {
list.remove(removeBlockIndex);
}
}
}
private static void report(ArrayList<byte[]> list) {
System.out.println(list.size());
}
}
This works very nice. You have to modify the MEMORY_BLOCK_MAX_SIZE and REMOVE_BLOCK_FACTOR to match your memory settings. I used a 8 GB heap for my numbers.
Nice things to note:
- Java GC really dislikes different sizes of memory block. This is why I randomize the memory block sizes to provoke as much GC work as possible
- The REMOVE_BLOCK_FACTOR controls the chance that a memory block is dereferenced and eligible for GC. It simply removes an item from the list (if the list is big enough). This has the nice characteristic the the chance that a block is removed is higher the more the list is filled.
29 January 2013
Office/Word 2003 in Windows 8
So the Windows 8 Upgrade Assistant tells me that I cannot use Office 2003:
Well I upgraded my Windows 7 to Windows 8 (that is I did NOT perform a clean install). And how does for example Word 2003 work:
Well it turns out that it works just fine! I haven't tried every feature, but everything I have tried appears to work. That includes Excel 2003 and Visio 2003.
Well I upgraded my Windows 7 to Windows 8 (that is I did NOT perform a clean install). And how does for example Word 2003 work:
Well it turns out that it works just fine! I haven't tried every feature, but everything I have tried appears to work. That includes Excel 2003 and Visio 2003.
17 January 2013
The Eclipse foreach template
There are many "hidden" features in Eclipse that are really good. Today I discovered the foreach template.
It works like this: place your cursor just above a array or Iterable (List) declaration. Press Ctrl + Space and press Enter. Eclipse will now create a for loop that you can use. It will use the Iterable variable that is closest.
Before:

After:
It works like this: place your cursor just above a array or Iterable (List) declaration. Press Ctrl + Space and press Enter. Eclipse will now create a for loop that you can use. It will use the Iterable variable that is closest.
Before:

After:
Subscribe to:
Posts (Atom)



