Ok, I've now twice wasted time on trying to figure this out and this time I'm writing it down, so I don't do it a third time :)
I recently added an eclipse project to SVN (it's already in perforce, my usual SC of choice) and after that my JAR export would fail with a bunch of "Resource is out of sync" errors. Since all the resources were .svn related, I blamed SVN and chased this down the wrong path for a bit.
Here's the simple solution: If you see a jar export fail because of "resource is out of sync", try doing a Refresh on the project before anything else. That should solve it.
Disclaimer: I've been trying to store some text resources in my jar so that i can easily package uncompiled content with my executable. This course of action seemed like the natural thing to do. However what I had to do to actually access this file and allow for different environments like running from eclipse vs. executing the jar makes me wonder if I'm missing some essential facilities. I.e. can eclipse build the jar and execute it instead of running it's class files, so that you can test jar stored executions as part of eclipses normal debug and excution? And is there some facility that let's you just say InputStream res = App.GetResourceStream()?. Well, in the meantime here's what i cobbled together to get this working, since my googling didn't come up with a single source that put it all together.
First thing, we need to determine where we are executing, both because its the base for finding our resource and because it tells us whether we're dealing with a directory hierarchy or a jar file:
ProtectionDomain protectionDomain = this.getClass().getProtectionDomain();
CodeSource codeSource = protectionDomain.getCodeSource();
URL location = codeSource.getLocation();
File f = new File(location.getFile());
Now we get an InputStream, depending on what environment we're in:
String resourcePath = "resources/xsl/register.xsl";
InputStream resourceStream = null;
if (f.isFile()) {
// it's a file, so we assume it's a jar and look for our
// resource as a JarEntry
JarFile jar = new JarFile(f);
JarEntry xslEntry = jar.getJarEntry(resourcePath);
resourceStream = jar.getInputStream(xslEntry);
} else {
// it's a directory, so we just append our relative resource
// path
resourceStream = new FileInputStream(f.getAbsolutePath() + "/"
+ resourcePath);
}
Now we have an InputStream and can ingest the file anyway we like.
Being an eclipse newbie, setting up third party JARs was a bit painful to figure out. Well, not painful as such, just painful once i tried to move the project across platforms.
See, I was using the External JARs... option in the Build Path dialog. But that set up absolute paths, which is a bad idea even if you stay on the same platform. Going across platforms C:\.. just wasn't an option. So i tried editing the .classpath by hand. That just created tied the path to the root. Finally I figure out that if i added a lib directory to the project, the JARs I put inside of it, were now browsable by the Add JARs option. Now everything build happily across Mac and Windows. Joy.
Last time I used Java, JAXB was just being released. At least at the time, it was all about Schema definition and code generation. I loved the concept of serializing straight into XML and back, but code generation always is a bit of a nasty beast, imho. Plus, adding custom code to your class was also annoying. You basically had to extend your generated class to add anything custom to it.
When I started working with .NET, I was pleasantly surprised by their Attribute driven approach. Now the code and the XML definition was in one place and no post processing was required.
Back in Java land, I thought that with Java 5.0's addition of Annotations, maybe the meta-data code-markup method had been picked up as well. Sure enough there is JAXB 2.0 Reflection. However, if all I want to do is some config files and maybe some data serialization without the full Web Services juggernaut, that seems like a heavy handed way of doing it.
A little further digging brought me to Simple. One tiny jar and you are ready to define, serialize and deserialize your classes. Woot. Sure, my .NET bias is showing, but I really like this approach so much better than starting at the XSD/DTD and generating code. And creating code that let's you move objects from one side to the other is dead simple:
java
@Root(name="example")
public class Example {
@Element(name="message")
private String text;
@Attribute(name="id")
private int index;
public Example() {
super();
}
public Example(String text, int index) {
this.text = text;
this.index = index;
}
public String getMessage() {
return text;
}
public int getId() {
return index;
}
}
C#
[XmlRoot("example")]
public class Example
{
private string text;
private int index;
public Example()
{
}
public Example(string text, int index)
{
this.text = text;
this.index = index;
}
[XmlElement("message")]
public String Message
{
get { return text; }
set { text = value; }
}
[XmlAttribute("id")]
public int Id
{
get { return index; }
set { index = value; }
}
}
The main difference is that the Simple approach doesn't require there to be a public setter on the data, which is actually kind of strange. How does deserialization set the field? Does it use reflection Regardless, two pieces of code, looking quite similar, allowing you to serialize a class from C# to Java and back without a lot of work.
I've been doing java again for a project for the last few weeks and it's been fun. You do get spoiled from the clean syntax C# Properties give you over the getter/setter pattern. And talk about notation differences. I'm so used to Pascal Case on everyting except for fields and parameters that writing Camel Case on methods is taking some getting used to again. And don't even get me started on switching back and forth between Eclipse and VS.NET several times a day. My muscle memory is in shock. But once you get your mind in the right frame for the idiosyncracies, everything else is so similar is scary, especially with the Java 5.0 additions.
The difference, however, between the two platforms that I was always on the fence about is Checked Exceptions:
In Java, I love that I can declare what exceptions a method may throw and the IDE can pick this up and let you make intelligent decisions. In C#, you have to hope there are some mentions in the docs and otherwise you just find out at runtime and either have a catch all or add individual catches as you find exceptions.
But then, checked exceptions are in my mind the single most responsible party for the good old catch {} gem. And it's unavoidable. There are a number of cases where a non-type-safe argument is required, which, if it was wrong, would throw an exception. However, most of the time that argument isn't dynamic, but some constant you define. Really you know that the exception you are forced to handle will never be thrown and you put a catch {} in there, feeling justified. Soon enough the guilt is gone and you start using it when you just don't feel like dealing with that exception right now. Suddenly you're swallowing exceptions that someone up the chain might have cared about or that should have legitimately bubbled to the top. Bah.
Being a rabid fan of anything that makes code requirements machine discoverable, not being able to declare my exceptions feels dirty. And even for human discovery, documentation isn't sufficient, since it only covers the surface level, i.e. what I throw. Now, if i use someone else's code in there, i need to hope they were also diligent and I have to add any exceptions they may throw and I don't handle to the ones i may throw. Yeah, thatdocumentation is highly likely to fall behind the reality of the code.
Wouldn't it be nice if we could declare our exceptions as informational. Like throws but you don't have to deal with it. Huh, wouldn't that be meta-data about your code, i.e. a perfect candidate for Attributes ne Annotations? I've seen rumblings here and there about this, but nobody's ever picked it up seriously, that I could find. I for one, would love it if I could say
[Throws("InvalidOperationException,FooBarException")]
public void SomeMethod() { ... }
and have the IDE pick up on it to let me know and optionally generate warnings about things I'm not catching. I think that would be the best of both worlds.