Archive
Eclipse + Android + SVN = fail
If you are developing a project in SVN (I’m sorry for your predicament) and using Eclipse, please heed my advice. Otherwise you could unintentionally delete your source directory during a routine cleanup.
Now, how could you possibly do that? you might wonder. Are you incompetent? Well, maybe, but not in this case. The situation was this: I was about to make a commit of some changes to the code and did a svn status before committing to ensure that everything was as I wanted it to be. I noticed that there were dozens of files in the bin directory that either had question marks next to them (.class files) or showed up with exclamation points next to them (indicating that SVN thought they’d gone missing). Given that the binary class files do not belong in version control, I went ahead and did a svn rm -rf bin (recursively delete all the files under bin). I went ahead and finished the commit. Later I went to make another commit and I got an error telling me that the src folder didn’t exist in the svn repository. Horrified, I my unix history and then the svn commit log:
529 svn rm –force bin/
530 svn ci -m “Bin should not be under version control.”
Revision 249
Author: ndunn
Date: Mon Jul 26 14:52:14 2010 UTC (62 minutes, 34 seconds ago)
Log Message:
Bin should not be under version control.
trunk/projname/src/ deleted
Um. What? I’m pretty sure bin != src. Well. You’d think that. But if you’re using Eclipse and haven’t dived in four menus deep, you’d be wrong.
You see, for some reason Eclipse copies all the files from the src folder into the bin folder when you build the project. Why it does that, I’m not sure. I’d love to know why. Regardless of the reason, all of the files in the src are copied. Including… the hidden .svn folders. These folders are how subversion keeps track of the changes to your files. The problem is, since the .svn folders were copied, and bin was deleted, it was exactly the same to svn as if I had deleted src. Which is why my src folder disappeared.
How do you work around this? Well, I mentioned earlier that by default eclipse copies all of the files from src to bin. You can add filters so that certain files/extensions are ignored, if you know where to look. In Eclipse, go to Preferences -> Java -> Building -> Output Folder and make sure that *.svn is on the line for filtered resources. It will prompt you to rebuild your project. Once it does so, you will not have this potential mistake looming over your head.
Finally, here’s the svn command you need to revert a folder if you accidentally delete it and check the deletion into source control. Let’s assume you deleted the folder in revision n. Then you want to fetch the status of that folder at n – 1
n = 249
svn copy -r248 -m "Restore deleted trunk/src" svn+ssh://username@company/path/to/trunk/src@248 svn+ssh://username@company/path/to/trunk/src
Thanks to the android developers group for helping me figure out what was going on; see here for details.
I have submitted a bug / feature enhancement request to the Eclipse developers so that the default behavior is a bit more sane. You can find that bug report here. The commenters mention that installing the svn plugin for Eclipse fixes the problem, but I don’t think I or anyone else should have to install something just to have sensible behavior.
The StackOverflow post giving a shorter synopsis of the problem can be found here.
Conclusion:
Lots of Android developers use Eclipse to develop their projects due to the plugin support available. I’d wager a fair number of them use SVN as well for their source control. They should be very wary about the default behavior of Eclipse, and ensure that they filter to remove .svn files from being copied over to their src folder. Take it from me – it’s not a good feeling seeing a commit message with your name on it deleting the src folder. Or you could use git and not have to worry about any of these problems…
How to make git use TextMate as the default commit editor
git config --global core.editor "mate -w"
Now when you do a git commit without specifying a commit message, TextMate will pop-up and allow you to enter a commit message in it. When you save the file and close the window, the commit will go through as normal. (If you have another text editor you prefer instead, just change the “mate -w” line to the preferred one)
For those curious what the -w argument is about, it tells the shell to wait for the mate process to terminate (the file to be saved and closed). Read this for more information about how to associate TextMate with various other shell scripts and programs.
Nerdy on so many levels
For those not hip to stupid Internet lingo: http://lmgtfy.com/?q=1337
How to: Interact with remote Unix Systems
If you’re a software developer or sysadmin, chances are that you will not always be working with a local machine. That is where remote access comes in. I’ve had to pick up how to do this through trial and error; hopefully this post will pull together information from all the disparate sources and will help newbies like myself learn a little more quickly.
This post will go through all the tools you will need to interact with remote Unix based systems while using Windows or Mac OSX. Why am I focusing on interacting with Unix based systems? Many of the computers you will want to access remotely will be running a variant of Linux (servers come to mind). Besides, I guarantee you will be a more productive programmer / computer operator if you learn Unix command line tools. I will be covering Unix command line tools in much greater depth in a later post.
Beginner
If all you need is to grab files off of a remote Unix computer or dump some files to said machine, you can use a client application to help. If you’re on Windows, you will want a copy of WinSCP. This is a GUI version of the command line tool secure copy (scp), and allows you to drag and drop files between your local machine and the remote computer. For users uncomfortable with command line tools, this is the easiest way to add and grab files to remote machines. WinSCP has some bizarre UI choices (the selection of file nodes is unlike anywhere else in the Windows OS) but it can be useful. For MacOSX you can use Fugu; it does much the same thing.
Intermediate
When copying and pasting files is not enough, you will need to roll your sleeves up and learn a few more tools. First, you need to get used to the idea of giving up your GUI windowing environment and interacting with a keyboard
The terminal. Learn to love it
First, you will need to learn how to navigate a Unix directory tree, as you will not have the nice GUI environment you are used to.
Nick@Macintosh-2 ~/Desktop/TestDir$ tree . . |-- SubFolder1 | |-- SubSubFolder1 | `-- test.txt |-- SubFolder2 `-- test.txt 3 directories, 2 files
I’m not going to duplicate all the information that’s already on the Internet about using the command line. Here’s a few commands you’ll absolutely need to know.
Command |
Description |
cd | change directory |
ls | list files in directory |
cp | copy files |
mv | move files |
mkdir | make directories |
Once you are comfortable moving around your own directory structure using the command line, you’re ready to interact with a remote machine.
SSH
See the man page for the full syntax, but the basic way to use ssh is as follows:
ssh username@remotemachine
where remotemachine is either the name of the machine, if it’s on your local network and is mapped to an IP Address, or the IP address. You must have an account on that machine, and permission to log in. You will be prompted for a password if necessary. There are plenty of guides online for how to use SSH, here’s a good intro guide.
Type ‘logout’ when you are finished.
Advanced
If you’re on a Linux box, you’ve probably already got screen installed. If you’re on Windows running Cygwin, there’s a patch to add screen support. If you’re on Mac, you can use MacPorts (one of my essential pieces of Mac software) to install screen:
port install screen
Command
|
Description
|
screen
|
Launches the screen program; you might see information popup describing the program
|
screen -S name
|
Creates a new screen session instance named ‘name’
|
screen -r
|
If there’s only one saved screen session, resume it; else displays the list of screen sessions available
|
screen -r text
|
Resume the screen session whose name includes ‘text’; if it’s ambiguous it will tell you so and you need to be more specific
|
While screen is running
Command
|
Description
|
Ctrl-a ? | Display all the keyboard commands |
Ctrl-a “
|
List all the current windows in the screen session
|
Ctrl-a A
|
Rename the current window
|
Ctrl-a k | Kill the current window (pops up a Dialog question) |
Ctrl-a d | Disconnect from the screen session; you can resume it later with screen -r |
Ctrl-a c | Create a new window |
Ctrl-a p | Go to previous window |
Ctrl-a n | Go to next window |
Ctrl-a S | Split the window |
Ctrl-a Q | Quit splitting the windows (go back to one) |
Ctrl-a Tab | Jump between split windows |
Ctrl-a a | Invoke a literal ctrl-a (jump to first character of input) |
If you’re a Unix guru who’s used to navigating through text with Ctrl-a to jump to the start of a line, this last command is very useful (and I just found it while researching this post; it was driving me nuts previously). On Windows the Ctrl-a a shortcut is not necessary; you can hit Home to jump to the front of the line. On a Mac, however, the Home key pages up.
Conclusion
Being able to interact with machines that are not right in front of you is a crucial skill to have in the IT business. It can also be useful if you’re in school and need to retrieve a file that you saved on a machine somewhere and that you don’t feel like walking across campus to access locally. There are all sorts of uses for the tools I’ve introduced here; hopefully this piques your interest and causes you to read more about them.
Android: Principle of least surprise violation in GPS emulation
Some of the most viewed posts on this blog have been about Android development, namely some workarounds for bizarre bugs that Google *still* has not fixed, months later. I haven’t touched Android in a few months, but recently have started to dive back in. Here’s yet another instance where an Android related piece of software performs completely counter-intuitively.
When developing an Android application, I often use the emulator rather than an actual hardware device. In order to test GPS related functionality, you can either send simulated GPS events through the Dalvik Debug Monitor Service (DDMS) via Eclipse or through the Android terminal via telnet. I’ll detail surprising bugs/defects in both ways.
DDMS
The DDMS Eclipse view is available after installing the ADT plugin, and it’s absolutely crucial in order to see logging messages produced from your application (“LogCat”). It also allows you to send GPS coordinates, as the following screenshot shows.
Unfortunately there is a bug in this software that drove me up the wall, and I never would have figured it out myself. I was running into the problem where the first GPS coordinate sent would be received by the emulator, but all subsequent ones would not. It turns out the problem has to do with locales and decimals being treated as commas, or vice versa. See the following Google bug report for more details. The bug has been open over a year; fortunately it looks like it’s slated to be fixed in the next SDK release.
Telnet
If you telnet into your emulator instance, you have access to the Android console environment.
telnet localhost 5554
Android Console: type ‘help’ for a list of commands
OK
One of the commands you can send is fix, which send a latitude longitude pair to the emulator. Well, that’s what I assumed it did. After wondering why all my locations were were coming out incorrectly, I read the documentation a little more carefully.
fix <longitude> <latitude> [<altitude>] | Send a simple GPS fix to the emulator instance. | Specify longitude and latitude in decimal degrees. Specify altitude in meters. |
There is a VERY strong convention to specify latitude before longitude. (“latitude and longitude” returns 4,240,000 results as opposed to 542,000 for “longitude and latitude”) Having this command take arguments in the opposite order is very surprising and counter-intuitive. I notice that the DDMS screen has it longitude, latitude as well, but even within the Android APIs, you specify the latitude first!
I realize I should have read the documentation first, but it still is a flaw that the software behaves in unexpected manners (it violates the Principle of Least Surprise/Astonishment), and inconsistent with how API calls in the rest of the OS work. If someone has an explanation for why it’s written this way, I’d love to hear it.
Edit: Later I learned that KML has the same convention, longitude followed by latitude. This corresponds with the x,y ordering conventional in math, so it’s perhaps not so surprising after all. This ordering problem is fairly minor in the grand scheme of things, and reflects more on my own inexperience with geospatial APIs than any fault of Android itself.
An introduction to Scala
An Introduction to Scala
Overview
- Introduction
- Why is it gaining popularity, and why should you care?
- History
- Functional programming
- Syntax
- Data structures
- Benefits
- Drawbacks
- Conclusion
Introduction
- Scala = scalable language.
- From scripts all the way up to enterprise
- Runs on JVM
- Combines functional and object-oriented paradigms
Scala was designed to be both object-oriented and functional. It is a pure object-oriented language in the sense that every value is an object. Objects are defined by classes, which can be composed using mixin composition. Scala is also a functional language in the sense that every function is a value. Functions can be nested, and they can operate on data using pattern matching. Language creator Martin Odersky
Why?
- Productive like a scripting language, but with type safety and speed
- You can express yourself in fewer lines of code than equivalent Java.
- “On average, Odersky predicts a 2x reduction in lines of code between a Java program and a Scala port.” Scala lift-off: Martin Odersky Keynote
- Less boilerplate
- Better type inferencing
- Well suited to multithreaded environments
- Actors and message passing
Less boilerplate
// Scala
case class Person(firstName: String, lastName: String)
// Java
public class Person implements Serializable {
private final String firstName;
private final String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Person withFirstName(String firstName) {
return new Person(firstName, lastName);
}
public Person withLastName(String lastName) {
return new Person(firstName, lastName);
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Person person = (Person) o;
if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
return false;
}
if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
return false;
}
return true;
}
public int hashCode() {
int result = firstName != null ? firstName.hashCode() : 0;
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
return result;
}
public String toString() {
return "Person(" + firstName + "," + lastName + ")";
}
}
Samples where Scala code is significantly shorter than Java
History
- Martin Odersky created it
- Functional programming and compiler background (wrote current javac reference compiler)
- Worked on adding generics to Java
- Design began in 2001, released in 2003
- Version 2.80 Final released July 14, 2008
Functional programming
- Avoid state and mutable data
- Every variable is a constant
- Lends itself to parallelization; avoid locking and deadlocks
- First-class functions – functions can serve as arguments and results of functions
- Recursion is primary tool for iteration
- Heavy use of pattern matching
- Lazy evaluation – infinite sequences
Who’s using Scala
- Twitter uses for performance critical code; replaces Ruby in that regard
- FourSquare uses Scala and Lift web framework
- Xerox uses Scala and Lift
- Etherpad uses Scala in its real time document collaboration software (acquired by Google for Google Docs; Scala code is now opensourced)
Syntax:
Hello world in Scala:
object HelloWorld extends Application {
Console.println("Hello World")
}
No semicolons needed
Variables declared with val and var
val x = 0 // immutable
var y = 0 // mutable
x = 1 // compiler error
y = 1 // fine
Type declarations occur after the variable
int x = 0; // Java
val x: Int = 0 // Scala
Generic type arguments occur within square brackets rather than angle brackets
List<Integer> intList = ...; // java
val intList: List[Int] = ..// scala
Array indexing is done through use of parentheses rather than square brackets
// Java
int[] x = {1,2,3,4};
x[0] // 1
// Scala
val x: Array[Int] = Array(1,2,3,4)
x(0) // 1
Method definitions
scala> def square(x:Int) = { x * x }
square: (Int)Int
scala> square(5)
res38: Int = 25
No such thing as a ‘void’ method, every method returns a value. void = “Unit” in Scala
scala> def printIt(x:Any) = { println(x) }
printIt: (Any)Unit
Type inferencing – note that I haven’t been declaring what types my methods take
// Compiler infers that the return type must be int
scala> def square(x:Int) = { x * x }
square: (Int)Int
// I can explicitly indicate what it returns if I prefer
scala> def squareExplicit(x:Int):Int = { x * x }
squareExplicit: (Int)Int
No need to explicitly return values
scala> def square(x:Int) = { x * x }
square: (Int)Int
scala> def squareExplicit(x:Int):Int = { return x * x }
squareExplicit: (Int)Int
// The result of last expression is returned.
Conditionals as values
// BAD. Java style, mutable value
var x = 0
if (someCondition) {
x = something
}
else {
x = somethingElse
}
// GOOD: Scala style, immutable
val x =
if (someCondition) {
something
}
else {
somethingElse
}
// or if short enough
val x = if(something) something else (somethingElse)
All operations are method calls
Scala doesn’t technically have operator overloading, because it doesn’t actually have operators in the traditional sense. Instead, characters such as +, -, *, and / can be used in method names. Thus, when you typed 1 + 2 into the Scala interpreter in Step 1 you were actually invoking a method named + on the Int object 1, passing in 2 as a parameter. As illustrated in Figure 3.1, you could alternatively have written 1 + 2 using traditional method invocation syntax (1).+(2).
“Programming in Scala, p. 39”
What good does that do me?
If your domain objects make sense to add, multiply, divide, etc., you can treat them in a much more natural way.
// BigInt is a wrapper around Java's BigInteger, providing arithmetic methods
scala> BigInt("103058235287305927350") + BigInt("288888203959230529352")
res16: BigInt = 391946439246536456702
// In Java you're stuck calling .add, .multiply, etc
scala> new java.math.BigInteger("103058235287305927350").add(new java.math.BigInteger("288888203959230529352"))
res21: java.math.BigInteger = 391946439246536456702
Data structures
Lists
More powerful than Java lists. Expose a whole raft of Functional Programming paradigms, such as map, reduce, filter, folds, etc.
// Note the syntax; you do not call "new". This is because there is
// an apply ("()") method defined in the List object.
scala> val a = List("hello","how","are","you")
a: List[java.lang.String] = List(hello, how, are, you)
// Explicit
val nums:List[Int] = List(1,2,3,4)
scala> a.size
res40: Int = 4
scala> a.mkString(" ")
res41: String = hello how are you
scala> a.map(x => x.toUpperCase())
res42: List[java.lang.String] = List(HELLO, HOW, ARE, YOU)
scala> a.map(x => x.length())
res43: List[Int] = List(5, 3, 3, 3)
scala> a.filter(x => x.startsWith("h"))
res44: List[java.lang.String] = List(hello, how)
scala> a.forall(x => x.length() > 0)
res46: Boolean = true
// Singly linked list
scala> a.head
res67: java.lang.String = hello
scala> a.tail
res68: List[java.lang.String] = List(how, are, you)
// add to head
scala> 1 :: List(2)
res70: List[Int] = List(1, 2)
// reverse
scala> a.reverse
res72: List[java.lang.String] = List(you, are, how, hello)
Tuples
Tuples are a good data structure to pack up multiple variables to return from a function, without the need to define a helper class to do so. Slightly syntax to create them, as well as to access the elements contained therein.
// Explicitly create the tuple; never really a need to do this
scala> val a:Tuple2[Int,Int] = (5,6)
a: (Int, Int) = (5,6)
// The parentheses indicate it's a tuple
scala> val b = (5,6)
b: (Int, Int) = (5,6)
// Yes, I know it's a strange syntax. And it's 1-based rather than 0-based. This is because Haskell has 1-based tuple ordering and Odersky wanted to stay true to that.
scala> a._1
res48: Int = 5
scala> a._2
res49: Int = 6
// You can have an arbitrary number of elements, of any type you want
val listTuple = (List(1,2,3), "hello", new java.awt.Color(255,0,0))
scala> val listTuple = (List(1,2,3), "hello", new java.awt.Color(255,0,0))
listTuple: (List[Int], java.lang.String, java.awt.Color) = (List(1, 2, 3),hello,java.awt.Color[r=255,g=0,b=0])
Maps
Scala provides immutable maps as well as a syntax for creating map literals.
scala> val theMap = Map("hello"->5,"world"->5)
theMap: scala.collection.immutable.Map[java.lang.String,Int] = Map(hello -> 5, world -> 5)
scala> theMap("hello")
res50: Int = 5
scala> theMap.getOrElse("world",2)
res51: Int = 5
scala> theMap.getOrElse("worldly",2)
res52: Int = 2
scala> theMap.keySet
res54: scala.collection.Set[java.lang.String] = Set(hello, world)
scala> theMap.values
res55: Iterator[Int] = non-empty iterator
scala> theMap.values.toList
res56: List[Int] = List(5, 5)
// Mutable map:
var mutableMap = Map[Int, String]()
mutableMap += (1 -> "1")
mutableMap += (2 -> "2")
Arrays
Internally map to Java arrays. Idiomatic Scala code tends to prefer Lists to Arrays, but they are necessary for interacting with a lot of Java code. Create in same way as lists.
scala> val array = Array(1,2,3)
array: Array[Int] = Array(1, 2, 3)
Benefits
-
Static type checking but with improved type inference
// Java
private Map wordCount = new HashMap();
// Scala:
var wordCount:Map[String, Int] = Map() -
Much faster than Python/Ruby and other interpreted languages, but just as expressive
- Duck typing support
- Conciseness
- Functions as first class objects; no need for anonymous classes and extraneous interfaces Unified types
- Traits are a cross between interfaces and abstract classes, allowing you to provide default implementations. Allows for ‘mix-in’ composition, as well. Solves problems with multiple inheritance, while giving flexibility. Avoid repeating yourself.
- Console REPL environment allows you to quickly iterate and test
- Of theoretical interest
- Combines functional and object-oriented in statically-typed environment
Drawbacks/Complaints
- Immaturity of tool chain
- Binary/source incompatibility from rapid change of language
- Type system is very complex
- Functional programming can be hard to wrap head around for people familiar with OOP
-
Syntax can be so concise as to be cryptic
For instance, the following example comes from StackOverflow post.
def scanLeft[a,b](xs:Iterable[a])(s:b)(f : (b,a) => b) = xs.foldLeft(List(s))( (acc,x) => f(acc(0), x) :: acc).reverse
And then use it like this:
scala> scanLeft(List(1,2,3))(0)(_+_) res1: List[Int] = List(0, 1, 3, 6)
Conclusion
Scala is a very intriguing language due to its combination of object orientation with functional programming concepts. The programmer is not forced to choose between the expressiveness of objects and immutability; he can switch between the two paradigms as the situation warrants.
While binary/source incompatibility is a very real problem for enterprise adoption, it is an issue that the creators are working on.
Scala provides a great framework in which to explore functional programming methods, especially through the use of the interactive console environment.
Resources
- Scala in the Interprise
- Martin Odersky’s Introduction to Scala video
- Scala for Java refugees
- Top five scripting languages on the JVM
- Scala history
- Scala language homepage
- Scala cheatsheet
- Scala FAQ
- Java, Grovvy & Scala: side to side1 2
- Lift
- Scala is unfit for serious development
- What is stopping you from switching to Scala?
Images:
XStream introduction and Java Collections serialization problem workaround
XStream is an open-source Java library for converting objects to and from XML. I’ll introduce how to use the library, show a problem I ran into that was a bit difficult to track down, as well as a workaround.
Library example
Imagine we are modeling a library in XML. This will be much simplified for the purposes of illustration. A sample XML library document might look like the following:
<library> <books> <book> <title>The Talent Code: Greatness Isn't Born. It's Grown. Here's How.</title> <author>Daniel Coyle</author> </book> </books> </library>
Let’s write some Java classes to represent this hierarchy.
public class Library { public List<Book> books; public Library(List<Book> books) { this.books = books; } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("Library with " + books.size() + " books:\n"); for (Book book : books) { b.append(book.toString()); // Skip a line b.append("\n"); } return b.toString(); } public static class Book { private String title; private String author; public Book(String title, String author) { this.title = title; this.author = author; } @Override public String toString() { return "\"" + title + "\" by " + author; } } public static void main(String[] args) { List<Book> books = new ArrayList<Book>(); books.add(new Book("The Talent Code: Greatness Isn't Born. It's Grown. Here's How", "Daniel Coyle")); Library lib = new Library(books); // Handles conversion of our objects into XML XStream stream = new XStream(new DomDriver()); String xml = stream.toXML(lib); // fromXML returns a general Object; need to cast it into a Library Library lib2 = (Library) stream.fromXML(xml); System.out.println(xml); System.out.println(lib); System.out.println(lib2); System.out.println("Libraries equal: " + lib.toString().equals(lib2.toString())); } }
This is not production worthy by any means; in general comparing the string representations of objects to test for equality is a very bad idea. But writing a foolproof equals method is very difficult and irrelevant to the point of this post. Here is the output produced by running the program:
<Library> <books> <Library_-Book> <title>The Talent Code: Greatness Isn't Born. It's Grown. Here's How</title> <author>Daniel Coyle</author> </Library_-Book> </books> </Library> Library with 1 books: "The Talent Code: Greatness Isn't Born. It's Grown. Here's How" by Daniel Coyle Library with 1 books: "The Talent Code: Greatness Isn't Born. It's Grown. Here's How" by Daniel Coyle Libraries equal: true
This is somewhat close to what we want, but not exactly. (Note that the ' stuff in the middle of the title is not a mistake; I was imprecise by including apostrophes in the original XML example. See here for an explanation of why apostrophes are treated specially in XML). Let’s start by aliasing some of the tag names. The relevant change is as follows:
XStream stream = new XStream(new DomDriver()); stream.alias("library", Library.class); stream.alias("book", Book.class);
Output:
<library> <books> <book> <title>The Talent Code: Greatness Isn't Born. It's Grown. Here's How</title> <author>Daniel Coyle</author> </book> </books> </library>
Initial success
OK, looks like things are working! But the way of constructing the list is not how I normally create lists. Let’s make sure the serialization works for alternative means of List construction.
Book talentCode = new Book("The Talent Code: Greatness Isn't Born. It's Grown. Here's How", "Daniel Coyle"); Library lib = new Library(Arrays.asList(talentCode));
For you who haven’t seen the use of Arrays.asList, it’s a method to convert an array (or varargs) into a List. It’s important for compatibility between array based and collection based frameworks. The corresponding method in the opposite direction, from Collections to arrays is the Collections.toArray. For the truly nerdy, here’s an interesting discussion of possible implications of calling toArray in a multithreaded environment.
Anyways, here’s the output.
<library> <books class="java.util.Arrays$ArrayList"> <a class="book-array"> <book> <title>The Talent Code: Greatness Isn't Born. It's Grown. Here's How</title> <author>Daniel Coyle</author> </book> </a> </books> </library> Library with 1 books: "The Talent Code: Greatness Isn't Born. It's Grown. Here's How" by Daniel Coyle Library with 1 books: "The Talent Code: Greatness Isn't Born. It's Grown. Here's How" by Daniel Coyle Libraries equal: true
Hmmm. The XML serialization/deserialization still works but it’s sure not pretty. What’s going on here? Why did it print “books” earlier but now it throws in all that ugly stuff about “java.util.Arrays$ArrayList”?
The answer is that XStream has a powerful set of converters that handle mapping Java constructs to and from XML. The relevant converter is the CollectionConverter. Here is the JavaDoc description, and the solution to the mystery:
Converts most common Collections (Lists and Sets) to XML, specifying a nested element for each item.
Supports java.util.ArrayList, java.util.HashSet, java.util.LinkedList, java.util.Vector and java.util.LinkedHashSet.
The problem is that creating a List via the Arrays.toList method does not create an instance of any of these classes. Instead, it returns an instance of an inner class named ArrayList (not to be confused with the java.util.ArrayList). Read the source of the java.util.Arrays class if you are interested in the implementation details.
What’s the workaround? Don’t blindly accept the list of books that is passed into the constructor. Instead, make a defensive copy.
public List<Book> books = new ArrayList<Book>(); public Library(List<Book> books) { this.books.addAll(books); }
Sure enough, this fixes the problem, as the actual class of the list of books is now one that the converter supports. Alternatively we could change the implementation of CollectionConverter to support the Arrays$ArrayList class, but it’s probably not worth it.
Conclusion
I introduced the XStream library for Java which handles the conversion of objects to and from XML. I presented a very simple Java example of a Library and its collection of books, as well as a problem that arises from the way XStream converts collections into XML.
NetBeans: Hang after debugging session
I’ve run into the issue a lot where I will use the debugger, stop the debugger, attempt to run the project again, and it just hangs. I always forget how to solve the problem so I figured I’d write it down for posterity.
In the build folder of your project, look for “testuserdir/lock”. If it exists, delete it.
I find the problem manifests itself when debugging Netbeans Platform modules; when you clean and build the module no errors or warnings are reported, but when you clean and build the main project, you get an error:
/Applications/NetBeans/NetBeans 6.8.app/Contents/Resources/NetBeans/harness/suite.xml:451: Will not delete /Users/nicholasdunn/Desktop/project/build/testuserdir because /Users/nicholasdunn/Desktop/project/build/testuserdir/lock still exists; kill any running process and delete lock file if necessary
BUILD FAILED (total time: 0 seconds)