Introduction
With NIO.2 we can easily determine the attributes of a file by using the java.nio.file.attribute package.
Various file systems have different properties associated with files but NIO.2 groups the attributes into views, each view is specific to a particular file system implementation.
NIO.2 comes with a set of views:
- BasicFileAttributeView: This view contains a set of common attributes supported by all filesystem implementations. The inner name of the attribute view is ‘basic’.
- DosFileAttributeView: This view contains a set of attributes specific to filesystems that implement DOS attributes. The inner name of the attribute view is ‘dos’.
- PosixFileAttributeView: This view contains a set of attributes specific to file systems that support the POSIX standards. The inner name of the attribute view is ‘posix’.
- AclFileAttributeView: This view is supported by all filesystems implementations that have the concept of ACL. The inner name of the attribute is ‘acl’.
- FileOwnerAttributeView: This view is supported by all filesystems implementations that have the concept of “ownership” over a file. The inner name of the attribute is ‘owner’.
- UserDefinedFileAttributeView
How do we determine what are the views supported by our filesystem ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.util.Set; public class MainClass { public static void main(String argv[]) { // Retrieves the default file system FileSystem fileSystem = FileSystems.getDefault(); Set<String> fileSystemViews = fileSystem.supportedFileAttributeViews(); // We iterate over the available file attribute views // of a file system for (String fileSystemView : fileSystemViews) { System.out.println(fileSystemView); } } } |
Output (I am using a Windows 7 machine):
1 2 3 4 5 |
acl basic owner user dos |
Everytime we want to access the view attributes of a file/folder, it is advisable to check if the file system supports the particular view. NIO.2 allows us to test this using the FileSystem.supportedFileAttributeViews() method .
Eg.:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package mainpack; import java.nio.file.FileStore; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.attribute.AclFileAttributeView; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.DosFileAttributeView; import java.nio.file.attribute.FileOwnerAttributeView; import java.nio.file.attribute.PosixFileAttributeView; public class MainClass { public static void main(String argv[]) { // Retrieves the default file system FileSystem fileSystem = FileSystems.getDefault(); Iterable<FileStore> fileStores = fileSystem.getFileStores(); for (FileStore fileStore : fileStores) { // Test if it supports BasicFileAttributeView System.out.println(String.format( "Filestore %s supports (%s) : %s", fileStore, BasicFileAttributeView.class.getSimpleName(), fileStore.supportsFileAttributeView(BasicFileAttributeView.class))); // Test if supports DosFileAttributeView System.out.println(String.format( "Filestore %s supports (%s) : %s", fileStore, DosFileAttributeView.class.getSimpleName(), fileStore.supportsFileAttributeView(DosFileAttributeView.class))); // Test if supports PosixFileAttributeView System.out.println(String.format( "Filestore %s supports (%s) : %s", fileStore, PosixFileAttributeView.class.getSimpleName(), fileStore.supportsFileAttributeView(PosixFileAttributeView.class))); // Test if supports AclFileAttributeView System.out.println(String.format( "Filestore %s supports (%s) : %s", fileStore, AclFileAttributeView.class.getSimpleName(), fileStore.supportsFileAttributeView(AclFileAttributeView.class))); // Test if supports FileOwnerAttributeView System.out.println(String.format( "Filestore %s supports (%s) : %s", fileStore, FileOwnerAttributeView.class.getSimpleName(), fileStore.supportsFileAttributeView(FileOwnerAttributeView.class))); System.out.println(); } } } |
Output:
1 2 3 4 5 6 7 8 9 10 11 |
Filestore (C:) supports (BasicFileAttributeView) : true Filestore (C:) supports (DosFileAttributeView) : true Filestore (C:) supports (PosixFileAttributeView) : false Filestore (C:) supports (AclFileAttributeView) : true Filestore (C:) supports (FileOwnerAttributeView) : true Filestore (D:) supports (BasicFileAttributeView) : true Filestore (D:) supports (DosFileAttributeView) : true Filestore (D:) supports (PosixFileAttributeView) : false Filestore (D:) supports (AclFileAttributeView) : true Filestore (D:) supports (FileOwnerAttributeView) : true |
Supported file attributes
Every view support file attributes.
Attribute | Returned Type | Comments |
“basic:creationTime” | FileTime | The exact time when the file was created. |
“basic:fileKey” | Object | An object that uniquely identifies a file or null if a file key is not available. |
“basic:isDirectory” | Boolean | Returns true if the file is a directory. |
“basic:isRegularFile” | Boolean | Returns true if a file is not a directory. |
“basic:isSymbolicLink” | Boolean | Returns true if the file is considered to be a symbolic link. |
“basic:isOther” | Boolean | |
“basic:lastAccessTime” | FileTime | The last time when the file was accesed. |
“basic:lastModifiedTime” | FileTime | The time when the file was last modified. |
“basic:size” | Long | The file size. |
Attribute | Returned Type | Comments |
“dos:archive” | Boolean | Return true if a file is archive or not. |
“dos:hidden” | Boolean | Returns true if the file/folder is hidden. |
“dos:readonly” | Boolean | Returns true if the file/folder is read-only. |
“dos:system” | Boolean | Returns true if the file/folder is system file. |
Attribute | Returned Type | Comments |
“posix:permissions” | Set<PosixFilePermission> | The file permissions. |
“posix:group” | GroupPrincipal | Used to determine access rights to objects in a file system |
Attribute | Returned Type |
“acl:acl” | List<AclEntry> |
“acl:owner” | UserPrincipal |
Retrieving file/folder attributes
There are two ways to extract those attributes:
- Getting a bulk of attributes using readAttributes() method ;
- Getting single attributes using getAttribute() method .
Retrieving bulk attributes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
package mainpack; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; public class MainClass { public static void main(String argv[]) { // File path Path path = Paths.get(System.getProperty("user.home"), "Downloads", "file1.txt"); // Getting bulk attributes BasicFileAttributes attributes = null; try { attributes = Files.readAttributes(path, BasicFileAttributes.class); } catch(IOException ioe) { ioe.printStackTrace(); } // Retrieving information StringBuilder outBuff = new StringBuilder(); outBuff.append("File: " + path); outBuff.append("\n"); outBuff.append("\t").append("tsize: " + attributes.size()); outBuff.append("\n"); outBuff.append("\t").append("creationTime: " + attributes.creationTime()); outBuff.append("\n"); outBuff.append("\t").append("lastAccessTime: " + attributes.lastAccessTime()); outBuff.append("\n"); outBuff.append("\t").append("lastModifiedTime: " + attributes.lastModifiedTime()); outBuff.append("\n"); outBuff.append("\t").append("isRegularFile: " + attributes.isRegularFile()); outBuff.append("\n"); outBuff.append("\t").append("isDirectory: " + attributes.isDirectory()); outBuff.append("\n"); outBuff.append("\t").append("isSymbolicLink: " + attributes.isSymbolicLink()); outBuff.append("\n"); outBuff.append("\t").append("isOther: " + attributes.isOther()); outBuff.append("\n"); System.out.println(outBuff.toString()); } } |
Output:
1 2 3 4 5 6 7 8 9 |
File: C:\Users\IBM_ADMIN\Downloads\file1.txt tsize: 0 creationTime: 2013-12-03T15:55:06.208828Z lastAccessTime: 2013-12-03T15:55:06.208828Z lastModifiedTime: 2013-12-03T15:55:06.208828Z isRegularFile: true isDirectory: false isSymbolicLink: false isOther: false |
We can also retrieve single attributes. Example:
1 2 3 4 5 6 7 8 |
... // The second parameter which is composed by two sections // [inner-view-name]:[supported attribute] Long size = (Long) Files.getAttribute(path, "basic:size", NOFOLLOW_LINKS); FileTime creationTime = (FileTime) Files.getAttribute(path, "basic:creationTime"); System.out.println("Size is: " + size); System.out.println("Creation time: " + creationTime); ... |
Updating file/folder attributes
The simplest way to update file attributes is by using the Files.setAttribute method.
In the following example we are going to modify the creation time of a given file:
1 2 3 4 5 6 7 8 9 10 |
... // BEFORE FileTime before = (FileTime) Files.getAttribute(path, "basic:creationTime"); System.out.println("Creation time (BEFORE): " + before); // AFTER Files.setAttribute(path, "basic:creationTime", FileTime.fromMillis(System.currentTimeMillis()), NOFOLLOW_LINKS); FileTime after = (FileTime) Files.getAttribute(path, "basic:creationTime"); System.out.println("Creation time (AFTER): " + after); ... |
Output:
1 2 |
Creation time (BEFORE): 2013-12-03T15:55:06.208828Z Creation time (AFTER): 2013-12-05T13:45:04.058Z |
Getting attributes of FileStores
To determine the default FileStore object we can invoke FileSystems.getDefault(), but it’s also possible to obtain the list of FileStores by iterating over the list we obtain calling FileSystem.getFileStores() .
Each file store object has dedicated methods for obtaining the name, type, totalSpace etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import java.io.IOException; import java.nio.file.FileStore; import java.nio.file.FileSystem; import java.nio.file.FileSystems; public class MainClass { public static void main(String argv[]) { // Obtaining the default file System FileSystem fileSystem = FileSystems.getDefault(); // Iterating over the list of existing file stores // and retrieve their informations StringBuilder outBuff = null; for (FileStore fileStore : fileSystem.getFileStores()) { try { // Initializing buffer outBuff = new StringBuilder(); outBuff.append("File store - ").append(fileStore).append("\n"); // Obtaining the total space outBuff.append("\t").append("Total space: "); outBuff.append(fileStore.getTotalSpace() / 1024); outBuff.append("\n"); // Obtaining used space outBuff.append("\t").append("Used space: "); outBuff.append((fileStore.getTotalSpace() - fileStore .getUnallocatedSpace()) / 1024); outBuff.append("\n"); // Available space outBuff.append("\t").append("Available space: "); outBuff.append(fileStore.getUsableSpace() / 1024); outBuff.append("\n"); // File store is readonly outBuff.append("\t").append("Read-Only: "); outBuff.append(fileStore.isReadOnly()); outBuff.append("\n"); System.out.println(outBuff.toString()); } catch (IOException e) { System.err.println(e); } } } } |
Output:
1 2 3 4 5 6 7 8 9 10 11 |
File store - (C:) Total space: 102399996 Used space: 47860936 Available space: 54539060 Read-Only: false File store - (D:) Total space: 210168828 Used space: 28760504 Available space: 181408324 Read-Only: false |
The NIO.2 Path Class
The Path class is considered to be the entry point for exploring the NIO.2 API. Basically every I/O operation in NIO.2 will exploit the facilities offered by this class.
Path is basically an upgraded version of the java.io.File class.
1. Getting the Path of the Home Directory When you want to obtain the path that points to a specific file in the Home directory, you can proceed as shown. The returned home directory is dependent on each operating system:
1 2 3 4 |
// Returns the folder 'Downloads' from the home directory Path path = Paths.get(System.getProperty("user.home"), "Downloads"); System.out.println(path); // Output is C:\Users\andreinc\Downloads |
2. Obtaining information about the Path: Path Root and Path ParentÂ
1 2 3 4 |
// Obtain the Path Root Path path1 = Paths.get(System.getProperty("user.home"), "Downloads"); System.out.println(path1.getRoot()); // Output is: 'C:\' |
1 2 3 4 |
// Obtain the path parent Path path2 = Paths.get(System.getProperty("user.home"), "Downloads"); System.out.println(path2.getParent()); // Output is: 'C:\Users\andreinc' |
3. Splitting a path in its name elements This is a nice feature that allows the programmer to split the path in it’s forming elements. For example if a file has the following path: ‘C:\Users\andreinc\Downloads\file1.txt’ the following function will retrieve the forming elements of the path, a List containing the following elements: [‘C:\’, ‘Users’, ‘andreinc’, ‘Downloads’, ‘file1.txt’] .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package mainpack; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class MainClass { public static List getPathElements(Path path) { List list = new LinkedList(); // The root element has to be added separately list.add(path.getRoot().toString()); for (int i = 0; i < path.getNameCount(); ++i) { list.add(path.getName(i).toString()); } return list; } public static void main(String argv[]) { // The location of the file Path path1 = Paths.get(System.getProperty("user.home"), "Downloads", "file1.txt"); List list = getPathElements(path1); Iterator it = list.iterator(); while (it.hasNext()) System.out.println(it.next()); } } |
And the output is:
1 2 3 4 5 |
C:\ Users andreinc Downloads file1.txt |
4. Getting the subpath We can extract a relative path using a subpath method. This method accept two parameters, the start (index) and end (index) in the subsequence of elements.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package mainpack; import java.nio.file.Path; import java.nio.file.Paths; public class MainClass { public static void main(String argv[]) { // The location of the file // C:\Users\andreinc\Downloads\file1.txt Path path1 = Paths.get(System.getProperty("user.home"), "Downloads", "file1.txt"); for (int i = 0; i < path1.getNameCount(); ++i) { for (int j = i + 1; j < path1.getNameCount(); ++j) { System.out.println(String.format("subpath(%d, %d) = %s", i, j, path1.subpath(i, j))); } } } } |
And the output is:
1 2 3 4 5 6 |
subpath(0, 1) = Users subpath(0, 2) = Users\andreinc subpath(0, 3) = Users\andreinc\Downloads subpath(1, 2) = andreinc subpath(1, 3) = andreinc\Downloads subpath(2, 3) = Downloads |
5. Combining two paths
This allows you to define a fixed root path and append to it partial paths.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package mainpack; import java.nio.file.Path; import java.nio.file.Paths; public class MainClass { public static void main(String argv[]) { // The location of the file // C:\Users\andreinc\Downloads\file1.txt Path fixedPath = Paths.get(System.getProperty("user.home"), "Downloads"); System.out.println("Fixed path is: " + fixedPath + "\n"); Path file1 = fixedPath.resolve("file1.txt"); System.out.println("File1: " + file1); Path file2 = fixedPath.resolve("file2.txt"); System.out.println("File2: " + file2); // You can also resolve a "sibling", a file existing at the same level Path file3 = file2.resolveSibling("file3.txt"); System.out.println("File3: " + file3); } } |
Output:
1 2 3 4 5 |
Fixed path is: C:\Users\andreinc\Downloads File1: C:\Users\andreinc\Downloads\file1.txt File2: C:\Users\andreinc\Downloads\file2.txt File3: C:\Users\andreinc\Downloads\file3.txt |
6. Comparing two paths
Two paths can be compared as objects, using the “equals()” function. This method is related to the “equals()” method of class Object, thus the compared paths are not required to exist, and this method does not check if the paths are the same file.
But sometimes we want to check if two Path objects represent the same file / folder . In this case we will need to use java.nio.File.Files.isSameFile() method.
Eg.:
1 2 3 4 5 6 7 8 9 10 |
// The location of the file Path fixedPath = Paths.get(System.getProperty("user.home"), "Downloads"); Path file1 = fixedPath.resolve("file1.txt"); Path file2 = fixedPath.resolve("file1.txt"); try { System.out.println("file1 isSameFile file2: " + Files.isSameFile(file1, file2)); } catch (IOException e) { e.printStackTrace(); } |
Output:
1 |
file1 isSameFile file2: true |
The Path class implements the Comparable interface, thus we can compare two paths by using the compareTo() method . The comparation will be lexicographical, so this will be useful for “sorting”.
7. Iterating over the elements of a Path
The Path class implements the Iterable interface, so we can use a foreach to iterate over the elements of a Path.
Eg.:
1 2 3 4 |
// The location of the file Path path = Paths.get(System.getProperty("user.home"), "Downloads", "file1.txt"); for(Path p : path) System.out.println(p); |
Output:
1 2 3 4 |
Users andreinc Downloads file1.txt |
Getting started with Apache Maven and Eclipse
Apache Maven is a popular build automation tool, for large Java Projects.
All major Java IDEs (IntelliJ IDEA, Eclipse and Netbeans) fully support Maven integration, by default or via plugins.
In order to get started with Maven you will need to:
1. Download Apache Maven from the original site, which is: http://maven.apache.org/ . Check for the Download section:
2. Extract the .zip file in your desired location (Eg. D:javatoolsapache-maven-3.1.0 )
3. The next step will be to setup the following system variables M2, M2_HOME, JAVA_HOME and also add the Maven bin directory to System Path. For managing the System Variables on my station I am using a dedicated software called Rapid Environment Editor:
If you don’t want to install Rapid Environment Editor, you can use the Windows built-in feature to edit System Variables:Â Control Panel -> System and Security -> System -> Advanced System Settings -> Advanced / Environment Variables .
4. Modify the location of Maven repository – this is the location where Maven installs all its artifacts (jars, etc.) . By default the location for this folder is ${user.home}/.m2/repository . On Windows machines this may raise issues, as most users keep their C: partition small enough and dedicated only for their Operation System. In order to modify this behavior edit %M2_HOME%\\confsettings.xml . In my case this location is D:\\java\\tools\\apache-maven-3.1.0\\conf\\settings.xml. The property you need to modify is called: localRepository :
In my case the new value for this property is:Â D:\\java\\tools\\apache-maven-3.1.0-repo .
5. The next step will be to test if maven was successfully installed. Open up a Command Prompt and type:
1 |
mvn -version |
If you’ve followed all the above mentioned steps the output should look like:
6. One of the cool features of Maven are the so-called Archetypes . Those are project structure / architecture templates that can save you a lot of time when you are defining boilerplate-like code. Right now Maven offers am impressive list of archetypes for defining all kinds of projects: JDBC Projects, Spring Projects etc. But in this tutorial we will use this feature in order to create a simple Java Project that are we going to import later into Eclipse.Â
In order to create a simple project use this command:
1 |
mvn archetype:generate -DgroupId=net.andreinc.tutorial -DartifactId=Tutorial -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false |
- groupId is be the package name ;
- artifactId is the name of the project ;
- archetypeArtifactId is the type of the archetype (in our case a simple Java Project).
If everything was successful (after some downloads in your repository) you will probably see something similar to :
If you analyze your folder structure you will see something like this:
7. The last step will be to generate the necessary descriptors for Eclipse so that our newly generated project skeleton will be recognized as an Eclipse project. In the project root folder:
1 |
mvn eclipse:eclipse |
8. The next step will be to import the project into Eclipse (File -> Import -> Existing Projects into Workspace):
And everything is done.
Adding custom annotations to your java beans
Java annotations are syntactic meta-information that can be added to your Java source code. You can annotate classes, methods, variables, method parameters and even packages.
The great advantage of Java annotations over javadoc tags is that those bits of information can be reflective and thus they can be made available to the VM at runtime (using the the Java Relection API).
Other than this, modern Java frameworks (like Spring) make heavy use of annotations in order to let the developer, extend, inject data and configure existent behaviors.
In this article we will define our own custom annotations, and we will use reflection to analyze and enhance the behavior of our Java beans at run-time.
Let’s suppose we want to write a mechanism that transforms (let’s say serialize) a given collection of java beans instances to a CSV file .CSV stands for Comma Separated Values. If you want to learn more about CSV files please check out this wikipedia article.
We don’t want to “serialize” all the fields, so will use annotations to mark only the fields we wish to “export”.
The first step will be the write the annotations class. We will call this one CSVExport.java :
1 2 3 4 5 6 7 8 |
package net.andreinc.utils; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface CSVExport { } |
As you can see all annotations related classes are included in the java.lang.annotation.*Â package. Other than this we will need to mark this annotation with a RetentionPolicy that will make it available at run-time, and we will specify that the annotation can only be used in conjunction with class methods (in our case those methods will be the bean getters).
At this point we will write a “model” java bean and we will mark the getters we want to serialize with our newly defined custom annotation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package net.andreinc.utils; public class TestModel { public String p1; public int p2; public Double p3; public TestModel(String p1, int p2, Double p3) { super(); this.p1 = p1; this.p2 = p2; this.p3 = p3; } @CSVExport public String getP1() { return p1; } public void setP1(String p1) { this.p1 = p1; } @CSVExport public int getP2() { return p2; } public void setP2(int p2) { this.p2 = p2; } @CSVExport public Double getP3() { return p3; } public void setP3(Double p3) { this.p3 = p3; } } |
Only the method that were annotated with @CSVExport will be serialized to the resulting file. If no annotations is present the specified getter method will be ignored.
The next step will be to write the class that actual export our collection. We will call this one CollectionToCSV.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
package net.andreinc.utils; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.PrintStream; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.lang.annotation.Annotation; import java.lang.reflect.*; public class CollectionToCSV { private Collection collection; public CollectionToCSV(Collection collection) { this.collection = (Collection) collection; } public void export(PrintStream out) { out = System.out; Iterator iterator = this.collection.iterator(); while (iterator.hasNext()) { try { out.println(buildCSVRow(iterator.next())); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IntrospectionException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private String buildCSVRow(T element) throws IllegalArgumentException, IllegalAccessException, IntrospectionException, InvocationTargetException { Method readMethod = null; Annotation[] annotations = null; Object value = null; StringBuilder buff = new StringBuilder(""); BeanInfo beanInfo = Introspector.getBeanInfo(element.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { readMethod = propertyDescriptor.getReadMethod(); if (null != readMethod) { annotations = readMethod.getAnnotations(); for (Annotation annotation : annotations) { if (annotation instanceof CSVExport) { value = readMethod.invoke(element); buff.append(value + ","); } } } } buff.deleteCharAt(buff.length()-1); return buff.toString(); } public static void main(String args[]) throws IllegalArgumentException, IllegalAccessException, IntrospectionException, InvocationTargetException { TestModel t1 = new TestModel("a", 1, 2.0); TestModel t2 = new TestModel("b", 2, 4.0); TestModel t3 = new TestModel("c", 3, 6.0); List tl = new LinkedList(); tl.add(t1); tl.add(t2); tl.add(t3); CollectionToCSV ccsv = new CollectionToCSV(tl); ccsv.export(System.out); } } |
The most important method buildCSVRow , as it iterates through the methods of the T.class (where T appears as a generic type, but in our case will be a TestModel instance), checks if the getter is marked with the @CSVExport annotation, and if the answer is yes the method will be invoked and the result will be included in our serialization.
If we run the main method the result will be:
1 2 3 |
a,1,2.0 b,2,4.0 c,3,6.0 |
If in the TestModel class we remove all the getters annotations nothing will be exported.
How to customize the font inside a JTextPane component (Java Swing) – Highlight Java Keywords inside a JTextPane
If you need to change the font, color, etc. of the text inside a JTextPane component you will basically need to follow the next steps:
1 2 3 4 5 6 7 8 9 10 11 12 |
private JTextPane textEditor; private StyledDocument textEditorDoc; ... textEditor = new JTextPane(); textEditorDoc = textEditor.getStyledDocument(); textEditor.getDocument().putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n"); ... StyleContext sc = StyleContext.getDefaultStyleContext(); // We will make the text blue (Color.blue) AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY,StyleConstants.Foreground, Color.blue); ... textEditorDoc.setCharacterAttributes(offset, length, aset, true); |
Where offset represents the starting position where you are going to insert the color and length represents the length (starting from the offset) that you wish color.
In the following scenario I will show you how to “highlight” the java keywords in a given text. To identify the keywords we will use Regular Expressions.
First we will have to a default color for text highlighting and blue is my color of choice.
1 |
public static final Color DEFAULT_KEYWORD_COLOR = Color.blue; |
The second step will be to define a regular expression that contains all the Java Keywords. For simplicity I chose to use static variables “attached” to my GUI class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public static final String[] JAVA_KEYWORDS = new String[] { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", "false", "null", "true" }; public static String JAVA_KEYWORDS_REGEX; static { StringBuilder buff = new StringBuilder(""); buff.append("("); for (String keyword : JAVA_KEYWORDS) { buff.append("\\b").append(keyword).append("\\b").append("|"); } buff.deleteCharAt(buff.length() - 1); buff.append(")"); JAVA_KEYWORDS_REGEX = buff.toString(); } |
The resulting string (JAVA_KEYWORDS_REGEX) will look like this (something that it’s not advisable to write by hand):
1 |
(\babstract\b|\bassert\b|\bboolean\b|\bbreak\b|\bbyte\b|\bcase\b|\bcatch\b|\bchar\b|\bclass\b|\bconst\b|\bcontinue\b|\bdefault\b|\bdo\b|\bdouble\b|\belse\b|\benum\b|\bextends\b|\bfinal\b|\bfinally\b|\bfloat\b|\bfor\b|\bgoto\b|\bif\b|\bimplements\b|\bimport\b|\binstanceof\b|\bint\b|\blong\b|\bnative\b|\bnew\b|\bpackage\b|\bprivate\b|\bprotected\b|\bpublic\b|\breturn\b|\bshort\b|\bstatic\b|\bstrictfp\b|\bsuper\b|\bswitch\b|\bsynchronized\b|\bthis\b|\bthrow\b|\bthrows\b|\btransient\b|\btry\b|\bvoid\b|\bvolatile\b|\bwhile\b|\bfalse\b|\bnull\b|\btrue\b)" |
For designing the GUI I’ve used an Eclipse plugin called WindowBuilder, and my component hierarchy looks like this:
The functions that are modifying the text are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public void updateTextColor(int offset, int length, Color c) { StyleContext sc = StyleContext.getDefaultStyleContext(); AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c); textEditorDoc.setCharacterAttributes(offset, length, aset, true); } public void clearTextColors() { updateTextColor(0, textEditor.getText().length(), Color.BLACK); } public void updateTextColor(int offset, int length) { updateTextColor(offset, length, DEFAULT_KEYWORD_COLOR); } |
And the action behind the button is: Read More