2024 DevOps Lifecycle: Share your expertise on CI/CD, deployment metrics, tech debt, and more for our Feb. Trend Report (+ enter a raffle!).
Kubernetes in the Enterprise: Join our Virtual Roundtable as we dive into Kubernetes over the past year, core usages, and emerging trends.
Director, Software Strategy at Lockheed Martin
About
I'm the author of The Book of Kubernetes, published in 2022 by No Starch Press. I've worked for over 25 years as a software developer, lead, architect, and manager. I've delivered real applications to production in Ada, Java, Python, and Go, amongst others, and have led multiple software teams in modernization efforts, incorporating cloud, microservice architecture, and containerization on complex programs. I'm an Agile and DevSecOps coach and an experienced trainer for Java, Ansible, containers, software architecture, and Kubernetes.
Stats
Reputation: | 5005 |
Pageviews: | 1.3M |
Articles: | 31 |
Comments: | 100 |
Articles
Refcards
Getting Started With Kubernetes
Persistent Container Storage
Trend Reports
Kubernetes in the Enterprise
In 2022, Kubernetes has become a central component for containerized applications. And it is nowhere near its peak. In fact, based on our research, 94 percent of survey respondents believe that Kubernetes will be a bigger part of their system design over the next two to three years. With the expectations of Kubernetes becoming more entrenched into systems, what do the adoption and deployment methods look like compared to previous years?DZone's Kubernetes in the Enterprise Trend Report provides insights into how developers are leveraging Kubernetes in their organizations. It focuses on the evolution of Kubernetes beyond container orchestration, advancements in Kubernetes observability, Kubernetes in AI and ML, and more. Our goal for this Trend Report is to help inspire developers to leverage Kubernetes in their own organizations.
Comments
Sep 23, 2019 · Alan Hohn
No problem. https://github.com/AlanHohn/karaf-greeter
Aug 29, 2019 · James Sugrue
Unfortunately extra CPU usage is unavoidable with encryption. You might try finding a separate application to do the HTTPS termination, such as HAProxy, and see if it uses less CPU. That separate application can forward traffic to Jetty. But I doubt that would save much CPU.
Jul 23, 2019 · Vivek Dhayalan
Docker multi-stage builds are in general a great way to reduce final image size, because you can start your final image from a very small upstream and include only what is needed to run your application (not what is needed to build it).
Jul 23, 2019 · Vivek Dhayalan
You might consider using a multi-stage Docker build: https://docs.docker.com/develop/develop-images/multistage-build/
This would allow you to run your "yarn install" in the first stage and copy the node_modules from it to the final stage. This will avoid the need to re-build and give you better configuration control (ensuring that your Docker image builds the same on everyone's machine, no matter what strange things they might have been doing to their local node_modules).
Aug 21, 2018 · Alan Hohn
Ansible tasks and roles are going to be easier to maintain, but anything you can do with Ansible, you can do with ordinary shell scripts. It's not really an Ansible question anymore, but to push files to remote machines I suggest you look at SCP.
Also, if you have control of the machine on which Jenkins is running the job, and you can install Python and Ansible, there's no reason you can't run an Ansible playbook directly from a regular Jenkins "Execute Shell Script" step. That does not require the Jenkins Ansible plugin.
Aug 03, 2018 · Alan Hohn
OK, that makes sense. I'm assuming you don't have access to the source code, so you can't modify it to accept parameters from the command line, the environment, or a properties file.
I'm also assuming that once you respond with the required values, the JAR file starts a long-running program and you need that program to stay running so you can talk to it. That means you can't just run it once, capture the results, and secure them in some other way.
Given those assumptions, you're pretty much limited to force-feeding input into your Java program when you start it from a JAR file. In that case, I would definitely look into using Expect to create a response file that will wait for your Java program to prompt you and then reply with the right information.
It's possible that you could just write your input into a plain text file, then pipe that to your Java program, but it's likely that Expect will be more reliable.
O'Reilly has a book on Expect if you're interested. Note that this is Expect the UNIX command, not Expect.js or anything like that.
Aug 02, 2018 · Alan Hohn
Hi Mahindra,
It's hard to tell exactly what you're trying to do based on your question, but if you're trying to perform a simple automation task you will probably find it easier to get going with Ansible because there's less to set up.
That said, neither is ideal for mimicking actual user input (i.e. typing). For that I would look at a tool called "expect".
Jan 21, 2018 · Alan Hohn
You certainly can test against your specific database as part of integration tests at the microservice or end-to-end test level. Or they can be part of a separate suite of unit tests (e.g. using DBUnit or similar tool) that aren't run as often. (For example, you might run your tests with mocks on every build, but your database integration tests only on the CI server.)
Of course, depending on your circumstances, you might decide that it's not too difficult to just use the real database for your unit tests, and not use mocking for this particular purpose. Remember that this is more of an educational example.
Your definition of the point of mocks is exactly right.
Jan 19, 2018 · Alan Hohn
It's an excellent question. With this kind of test, there are some things we are testing and some things we are not testing.
We are not testing the validity of the SQL statement created by our Code Under Test. We could test the validity of that (by being a little stricter in how we set up the mock) but that would make the test more brittle when we need to change the SQL statement in some way (e.g. for change in SQL dialect or for performance).
However, we are testing some important things. Since createAndRetrievePerson() performs a create first, then a retrieve, we're testing that on a create, all of the fields are being pulled from the object and put into the database, and that on a retrieve, all of the fields are being pulled from the database and put into the object. If we added a field to our Person object, added it to the test, but left it out of either create() or retrieve() in PersonDao, we would get a test failure.
So we're doing a decent job of testing the "object relational mapping" aspect of our DAO, which is worth something. And we can do it without needing a real database, not even an in-memory one, which means our tests are very easy to set up and are very fast.
If PersonDao was production code instead of an example, we would also check to make sure the right ID is being passed to the prepared statement on retrieve, that retrieving a non-existent object does what we expect, that our code does the right thing if it can't get a database connection, and a few other things. All those things can also be done using mocks.
It still wouldn't replace a test against a real database. But it would mean that our test against a real database could focus on whether we got the SQL right, which means that "real database" test would be simpler and could focus on the 'happy path' (because our mock test already hit things like failure to talk to the database, which can be hard to simulate reliably in the middle of an automated test).
Aug 08, 2017 · Arran Glen
I think the third code block (execute the alias) should be "dockviz images -t".
And unfortunately that echo command will clobber your ~/.bash_profile. I think you wanted to append with ">>".
May 16, 2017 · Alan Hohn
There doesn't appear to be a flag for Pyresttest to produce CSV, HTML, or a similar kind of output like JSON. Other than asking the author if it's something that can be added, the only other thing I can recommend is calling the relevant logic yourself from a Python program.
If you look at util/pyresttest within the source code, you can see it delegates to pyresttest/resttest.py. That file contains the logic for running the tests and printing the responses.
Jan 21, 2017 · Sibanjan Das
If I understand your two cases correctly, you about doubled the amount of data and it took about twice as long. That shows that it's O(n) but it still sounds I/O bound to me.
Jan 19, 2017 · Sibanjan Das
[Comment size limit]
Not that I'm trying to play the "my language is faster" game, since it would be easy to beat my code. The key here is that both of us are probably I/O bound. If there's an improvement in this code, it's that it doesn't wait until the end to write out each row.
If you go to a Spark version it will be important to make sure that there isn't a similar buffering step where you hold all the rows in memory (even for a partition of the rows in a parallel process) before writing them to disk.
Jan 19, 2017 · Sibanjan Das
Thanks for putting this together!
You probably were interested in using Scala for the sake of expanding knowledge of Scala, which is to be commended. You might also want to have Python in your toolbox for these kinds of "utility" programs. See what you think of this:
https://gist.github.com/AlanHohn/293c98f9dadfc67443b8078d843d4401
On my four-year-old i5 with 4 GB of RAM it took me under 2 minutes to run this code, with a 20GB network file copy going on in the background.
Oct 31, 2016 · Nicole Wolfe
If you control the execution environment of your Java program, you might look at the javax.net.ssl.keyStore and ...trustStore system properties. Won't save you from making keystores, but it does remove the manual coding to load them.
Oct 26, 2016 · Alan Hohn
Thanks!
Oct 14, 2016 · Michael_Gates
Silly DZone comment limit.
I agree with your main argument that we should Version Everything. Enough stuff can already go wrong in production without adding instability. I just don't know that we'll ever be able to avoid all cases where things fail in production, and only in production.
Oct 14, 2016 · Michael_Gates
Computer behavior may not be random, but from the perspective of a system, inbound data effectively is with respect to timing and content. No matter how identical our test environments, You Aren't Gonna Be Able to Test All Cases (YAGBATTAC). Blue/green deployment is a good practice when downtime is unacceptable.
Using a whole separate data center and a 48-hour cutover does seem a little excessive though.
Oct 03, 2016 · Alan Hohn
Thanks for taking the time to write.
Try this example:
https://gist.github.com/AlanHohn/bf9ea24bc1e728c2192a11353d69b5c0
The difference is that Arrays.stream() on an array of Integer objects returns a Stream<Integer>, while Arrays.stream() on an array of primitive int returns an IntStream, which has the sum() method. Auto-unboxing unfortunately does not work on arrays.
Sep 29, 2016 · Cliff Hall
Thanks
Sep 29, 2016 · Cliff Hall
Are you concerned that instead of paying your cloud provider for CPU cycles, you'll end up paying heavily for network traffic?
Aug 29, 2016 · Alan Hohn
Lots of value! I needed some intelligent back and forth to figure out what I meant. Thanks for reading and for making the discussion so much better.
Aug 29, 2016 · Alan Hohn
We seem to be writing past each other; probably I'm not doing a good job explaining where I'm going. Let me try again.
The system you seem to be envisioning is one where the components can communicate across a network or at least across process boundaries (in order to meet your interface requirements). Basically, you seem to be describing the kinds of systems that work on the Internet.
For those systems, I freely agree that a microservices architecture is an excellent approach. But I submit to you that what you did is exactly what I describe in my article—you identified One Concept for the system. If a new person joined the team, you would start by saying "Microservices: No Shared Code; Narrow Interfaces; Common Protocols". They would now be equipped to make decisions about new components that are consistent with your vision, which is exactly the test I identified in my article. We could argue about naming that One Concept; I might label it "Nulla poena sine lege" but that's because I'm an insufferable show-off. Even without a label it's clearly a single unifying concept for that system.
And I really do think you're right in your comments. I wish architects focused more on identifying the system's philosophy (One Concept under another name) and less on identifying the One Framework That This Time Will Solve Our Problems. The only thing I really disagree with in your comments is the implied notion that every system is going to fit under the specific concept you identified. Imagine a system that needs to sample information from the hardware, run it through a series of computations, and make a decision about what to do next, all in 500 microseconds—guaranteed. An architect that chose microservices for that system would be criminally negligent (maybe literally if it's a pacemaker). Instead, I would expect that architect to express a system concept that helped implementers make smart decisions about memory allocation, inter-thread communication, and I/O, since those are the areas that produce jitter and ruin hard real-time systems.
So there still seems to be some value in articulating a concept for a system, and it's not going to be the same one every time.
Aug 28, 2016 · Alan Hohn
I don't know that this is different from what I said; for the system, or system of systems, you describe, the "one concept" would be Language Agnostic Microservices.
But I'm not convinced this is the answer in all cases. I think it goes back to what I said in a previous article about there being more than one kind of simplicity. What you suggest is very simple to enforce organizationally, so you might say it has simplicity of governance. However, there's a tradeoff, which is that it's very likely to be difficult for people to move around between teams, and relatively difficult to hire into the company, because of the many frameworks and languages in use.
I understand that hiring for expertise in a language or framework is overdone, but sometimes we professional developers underestimate the value of language expertise. Look through my article history and you'll see me writing in Java, Go, Python, and probably some others, but Java is the only language where I qualify as expert, and that means only my Java code (if I do say so myself) is world-class quality. By letting each team pick whatever language or framework they wanted, we would lose a logistical simplicity. So while you could adapt your technology quickly, I'm not sure you could adapt your people as quickly.
Also, not all software work is created equal. My company generally builds systems where we deliver source code (with some kind of rights) to our customers so they can do their own maintenance. Delivering the kind of heterogeneous system you describe would be looked at askance as a maintenance challenge.
Jul 31, 2016 · Alan Hohn
Very well said; thanks to both of you for the thoughtful commentary.
Jul 19, 2016 · Dave Fecak
[small comment size limit]
Instead I would suggest overriding the name used for the box like this:
You can see a full example with multiple VMs here:
https://github.com/AlanHohn/vrrp-lab/blob/master/Vagrantfile
Jul 19, 2016 · Dave Fecak
I really wouldn't recommend doing it this way. By changing the ID to the ID of the original "ubuntu-xenial-16.04-cloudimg" VM, you are telling Vagrant to use the same VirtualBox VM for every xenial64 Vagrant VM on your system.
So if you have a Vagrantfile in different directories, you will really only have one VM and any changes you make (whether directly or with a provisioner) will affect all of them. Additionally, Vagrant is likely to get very confused about VM state, because that is stored in the .vagrant directory underneath each directory with a Vagrantfile.
Jul 07, 2016 · Duncan Brown
Interesting idea, but I'm having a hard time picturing it in practice: "Hello, I'm your new DBA. As one of my first acts, I'd like to install this tool on your company's network. It's different from what your company has selected, but even though I'm new I know it's better for your systems. What's that? Of course I verified the license. No need to check with your lawyers. And yes this disc is virus free, trust me.
Maybe it would be clearer with an example of a tool that would make someone better but wouldn't trip those major red flags.
Jun 21, 2016 · Alan Hohn
Hi Joel,
Sorry to be a little late to see your comment.
Alpine is a little different from other distributions of Linux you may have seen or used, so it's important to look at Alpine-specific pages. You can use pages that describe procedures for other distributions, but you might have to change the commands, and things like configuration files might be in different places.
Overall, I found the Alpine wiki to be a great resource. To do the installation, start with https://wiki.alpinelinux.org/wiki/Installation. Alpine calls a regular installation to a disk a "sys" install.
There are three important commands to learn when setting things up:
apk: This is your installer. When you boot from the live boot disk, Alpine will configure itself to install from the disk, so you can start installing some things right away. You use "apk add" with the package name(s) to install packages.
setup-alpine: To install a package that is not on the disk, you'll need to run setup-alpine first to configure the network and the Internet source for packages.
rc-update: This is the "set up a service" command. It tells Alpine what to run at boot time. The package you install (like wpa_supplicant in the article) needs to have an "rc script" in order for this to work.
May 23, 2016 · Grzegorz Ziemoński
P.S. It's worth saying again that I think the fault is with my piece for not being clear enough in what I was saying. Also, I invite everyone to read the comments from my piece, where people point out that another key reason why design patterns are good is shorthand communication, which is an excellent argument for Grzegorz's statement in favor of using pattern-specific naming.
May 23, 2016 · Grzegorz Ziemoński
[continued; silly DZone character limit]
4. Slavish adherence to the exact code from the GoF or other design patterns book will result in poor code, but recognizing and applying the pattern, even if the implementation looks different, will result in joy and happiness.
A "blueprint" is a document that must be followed exactly. So design patterns are good, but they are not blueprints.
May 23, 2016 · Grzegorz Ziemoński
It's pretty clear I didn't get across the point of my piece. Not surprising; I can be guilty of needless obscurity. Though I didn't say what you say I said.
Let me summarize my point, since I think we don't really disagree.
1. Design patterns are good.
2. A key reason why design patterns are good is that they present an approach to a set of similar problems.
3. This means that understanding design patterns can help you write good code even if the code you write doesn't look lilke the Official Canonical Version of the Design Pattern from the GoF book.
May 06, 2016 · Alan Hohn
Well, if each of those is really only used one place, there wouldn't be any search/replace happening if they needed to change.
But I can see keeping these, even though some like NUMBER_OF_DAYS_IN_WEEK are not going to change, if they are used in math in a way that isn't immediately clear why there would be a '7' stuck in there.
So I think it would depend on how you used it in the code. If it's used to set a non-obvious default value in one place, it is much better to keep it in the code.
defaultFont.setSize(10);
defaultFont.setSize(DEFAULT_FONT_SIZE);
The second one is silly.
I'm not arguing absolutely that you should only make constants out of things when you use them more than once. I'm saying that the "Magic Numbers Are Bad" folks are taking a good practice too far.
May 06, 2016 · Alan Hohn
Fair enough. And I wouldn't advocate using the term "strategy" in the code, for exactly the reason you give.
May 06, 2016 · Alan Hohn
Sure, I'll buy that. But I also think patterns work as a mental tool for quickly finding solutions to problems out of a large solution space. And in that sense what is being implemented here is a "strategy-like" approach to solving the problem.
Mar 16, 2016 · Alan Hohn
Thanks, I'm glad it was interesting.
I'm interested that your decompiler showed the StringBuilder; when I ran it through JD mine definitely came back as concatenation. I guess it's more evidence that they really are equivalent.
Mar 02, 2016 · Alan Hohn
Definitely agree. There's a certain twist of mind that's required to "see" something as an LP or IP but once you've learned it a lot of things open up.
And thanks for not slamming me for failing to mention that this example is really integer programming; I just couldn't figure out how to get that in without making the discussion even denser. :-)
Feb 18, 2016 · Alan Hohn
Thanks! You're right that the part I was replacing was a little friendlier in handling. I haven't gotten into all of the acetone and similar processing, so this would be a nice compromise.
Feb 18, 2016 · Alan Hohn
I was doing some unrelated research today and learned/remembered that Vagrant has an "Ansible local" provisioner that runs Ansible on the VM. So it would be possible to make a VM provisioned with Ansible that similarly had no dependencies beyond Vagrant+VirtualBox. But it would still come down to which tool someone liked better, or which tool the team is already using.
Feb 18, 2016 · Alan Hohn
Maybe I've just gotten used to seeing StringBuilder used when there are more than a couple strings to be combined that it doesn't read unclearly to me. I agree that it's not worth wasting developer cycles to optimize it.
Feb 18, 2016 · Alan Hohn
I would call it not so much an item of textbook knowledge but more a piece of "received wisdom". In my experience it has been a widespread view, and I think Google bears me out, though I will grant you that sites like StackOverflow and books like Effective Java handle it very well.
Feb 12, 2016 · Alan Hohn
Thanks, good read. Interesting that the discussion was largely about technical limitations; my discussion was about philosophical reasoning. I don't think I originated the idea that Puppet avoided direct http downloads because of concern over MITM, but I'm not sure where I read it.
Anyway, really glad that feature is coming. My workarounds were hideous.
Feb 09, 2016 · Alan Hohn
Good argument, thanks!
Feb 27, 2015 · Allen Coin
I don't think it's necessary to go that far to coordinate these two ideas.
The global optimum of an optimization function (linear, convex, other) is at the edge of the constraint envelope by definition. If you're not at the edge of the constraint envelope, there is an improving direction (some change in the input vector that results in a better output value).
That said, almost all optimization functions have multiple, usually many, input parameters. And it is usually true that the global optimum is found where the input parameters are somewhere in the middle of their range.
So I think what this law is saying is that you won't usually find an optimum solution if you crank some or all of the input parameters up to some extreme. This matches what engineers think intuitively, which is that there tend to be tradeoffs between the various knobs we can turn in any problem.
Oct 20, 2014 · Tony Thomas
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · Tony Thomas
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · Tony Thomas
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · Tony Thomas
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · James Sugrue
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · James Sugrue
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · James Sugrue
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · James Sugrue
That's a great point, thanks. Caliper had to run the "concatenation" test multiple times because it kept getting interrupted by GC.
Oct 20, 2014 · Tony Thomas
There's an example of that in my test class, and I measured it. It is indeed just as fast as if-then.
I just mentioned it in passing in the blog post; probably should have given it more play and shown a sample.
Oct 20, 2014 · Tony Thomas
There's an example of that in my test class, and I measured it. It is indeed just as fast as if-then.
I just mentioned it in passing in the blog post; probably should have given it more play and shown a sample.
Oct 20, 2014 · Tony Thomas
There's an example of that in my test class, and I measured it. It is indeed just as fast as if-then.
I just mentioned it in passing in the blog post; probably should have given it more play and shown a sample.
Oct 20, 2014 · James Sugrue
There's an example of that in my test class, and I measured it. It is indeed just as fast as if-then.
I just mentioned it in passing in the blog post; probably should have given it more play and shown a sample.
Oct 20, 2014 · James Sugrue
There's an example of that in my test class, and I measured it. It is indeed just as fast as if-then.
I just mentioned it in passing in the blog post; probably should have given it more play and shown a sample.
Oct 20, 2014 · James Sugrue
There's an example of that in my test class, and I measured it. It is indeed just as fast as if-then.
I just mentioned it in passing in the blog post; probably should have given it more play and shown a sample.
Oct 20, 2014 · Tony Thomas
Yes, the template's better if your API has it, and you can use it (not every value has a properly formatted toString()). Otherwise, if-else is way better from a numbers standpoint, though I agree it isn't the most attractive thing in the source.
Cheetahs have managed the perfect balance between beauty and speed. The rest of us have to work at that tradeoff.
Oct 20, 2014 · Tony Thomas
Yes, the template's better if your API has it, and you can use it (not every value has a properly formatted toString()). Otherwise, if-else is way better from a numbers standpoint, though I agree it isn't the most attractive thing in the source.
Cheetahs have managed the perfect balance between beauty and speed. The rest of us have to work at that tradeoff.
Oct 20, 2014 · Tony Thomas
Yes, the template's better if your API has it, and you can use it (not every value has a properly formatted toString()). Otherwise, if-else is way better from a numbers standpoint, though I agree it isn't the most attractive thing in the source.
Cheetahs have managed the perfect balance between beauty and speed. The rest of us have to work at that tradeoff.
Oct 20, 2014 · James Sugrue
Yes, the template's better if your API has it, and you can use it (not every value has a properly formatted toString()). Otherwise, if-else is way better from a numbers standpoint, though I agree it isn't the most attractive thing in the source.
Cheetahs have managed the perfect balance between beauty and speed. The rest of us have to work at that tradeoff.
Oct 20, 2014 · James Sugrue
Yes, the template's better if your API has it, and you can use it (not every value has a properly formatted toString()). Otherwise, if-else is way better from a numbers standpoint, though I agree it isn't the most attractive thing in the source.
Cheetahs have managed the perfect balance between beauty and speed. The rest of us have to work at that tradeoff.
Oct 20, 2014 · James Sugrue
Yes, the template's better if your API has it, and you can use it (not every value has a properly formatted toString()). Otherwise, if-else is way better from a numbers standpoint, though I agree it isn't the most attractive thing in the source.
Cheetahs have managed the perfect balance between beauty and speed. The rest of us have to work at that tradeoff.
Oct 23, 2013 · Juozas Kaziukenas
Thanks, nice to hear. I may add a couple chapters related to how to undo things; like you say there are a huge number of possible scenarios.
If I could find a simple way to explain how to find detached commits, I'd definitely write that up. The times I've really messed myself up with Git and had to resort to extraordinary measures to get things back have all been related to detached commits or a detached HEAD.
Oct 23, 2013 · Juozas Kaziukenas
Thanks, nice to hear. I may add a couple chapters related to how to undo things; like you say there are a huge number of possible scenarios.
If I could find a simple way to explain how to find detached commits, I'd definitely write that up. The times I've really messed myself up with Git and had to resort to extraordinary measures to get things back have all been related to detached commits or a detached HEAD.
Oct 23, 2013 · Allen Coin
Thanks, nice to hear. I may add a couple chapters related to how to undo things; like you say there are a huge number of possible scenarios.
If I could find a simple way to explain how to find detached commits, I'd definitely write that up. The times I've really messed myself up with Git and had to resort to extraordinary measures to get things back have all been related to detached commits or a detached HEAD.
Oct 23, 2013 · Allen Coin
Thanks, nice to hear. I may add a couple chapters related to how to undo things; like you say there are a huge number of possible scenarios.
If I could find a simple way to explain how to find detached commits, I'd definitely write that up. The times I've really messed myself up with Git and had to resort to extraordinary measures to get things back have all been related to detached commits or a detached HEAD.
Oct 19, 2013 · Esther Schindler
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Esther Schindler
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Esther Schindler
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Esther Schindler
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Esther Schindler
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Esther Schindler
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Abhijeet Dalal
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Abhijeet Dalal
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Abhijeet Dalal
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Abhijeet Dalal
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Abhijeet Dalal
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 19, 2013 · Abhijeet Dalal
Abhijeet,
Thanks for the kind words! I liked your post; it's clear that you're trying to think about the right way to do something. And these kinds of things are hard to get right.
The Javadocs for the Object class have a really good description of what rules should be followed when writing hashCode() and equals(). Where possible, hashcode() should be consistent with equals(). If two objects return true from equals(), they MUST return the same hashcode(). The rules are looser the other way, but if two objects return false from equals(), they should return different values from hashcode() where practical.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
In your case, because you didn't make equals() return true for <A,B> and <B,A> you get two map entries. However, you're taking away a little bit of the efficiency of the map because they wind up in the same hash bucket and HashMap has to do some extra work to keep them separated.
The implementation for Google's Table and Apache's MultiKeyMap are probably way better and more efficient than mine. The MultiKeyMap appears to use XOR in its hashcode(). You can see it here:
http://code.ohloh.net/file?fid=uwUNbunte4axGKi7fSolSmyN3ks&cid=YB-GWSWTwck&s=&browser=Default&fp=310491&mp&projSelected=true#L244
XOR is commutative and associative, so what Apache is saying is that the keys can come in any order and they will be treated as the same. But their equals() method says something different! Those guys are smart, so I figure they assumed that the same keys in a different order was low-probability and a more efficient hash function was more important.
Anyway, I enjoyed your post and thinking about the questions you raised.
Oct 13, 2013 · Esther Schindler
Won't this return the same hashcode for <A,B> as it will for <B,A>?
I think you want something like the example from Joshua Bloch's Effective Java:
I also think there's something odd with your equals() method. If I read it right, it will consider (null,null) equal to any other key. Assuming you want to treat null as equal with itself, which is uncommon but desired in some cases, I suggest something more like this. I haven't tested it, so treat with caution.
Oct 13, 2013 · Abhijeet Dalal
Won't this return the same hashcode for <A,B> as it will for <B,A>?
I think you want something like the example from Joshua Bloch's Effective Java:
I also think there's something odd with your equals() method. If I read it right, it will consider (null,null) equal to any other key. Assuming you want to treat null as equal with itself, which is uncommon but desired in some cases, I suggest something more like this. I haven't tested it, so treat with caution.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · Mr B Loid
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 09, 2013 · mitchp
Yep, exactly, thanks.
I've been lazy and been running it within Eclipse using Eclipse's Maven support, just running the main() in EmbeddedServer. I really ought to get Maven making an executable JAR that could be run anywhere - the idea is to be independent of jetty:run.
Oct 07, 2013 · Allen Coin
Thanks! I wrote about the standard collections because I figured people who are out looking for collections libraries already know when the standard collections are slow :-)
GapList seems like a really cool approach and I'm happy to have heard about it.
Oct 07, 2013 · Allen Coin
Thanks! I wrote about the standard collections because I figured people who are out looking for collections libraries already know when the standard collections are slow :-)
GapList seems like a really cool approach and I'm happy to have heard about it.
Oct 06, 2013 · mitchp
Absolutely, and thanks for the reply. I happened to think Digester was pretty cool in this case, but the JAXB implementation (which I think is what you're suggesting) would definitely be elegant as well.
I became accustomed to Digester back before JAXB was part of Java (I'm really dating myself there), but I find myself continuing to use it because of the looser tie between the XML and the Java. I'm sure it's just my own lack of experience, but I find it hard to map XML to Java using JAXB unless the Java and the XML are really similar in structure -- that is, where elements map to classes and attributes map to properties. I've used Digester in cases where the Java and the XML look nothing alike and was pleased. Definitely not trying to say, "this is better than that," just saying, "I like this because..."
Oct 06, 2013 · mitchp
Absolutely, and thanks for the reply. I happened to think Digester was pretty cool in this case, but the JAXB implementation (which I think is what you're suggesting) would definitely be elegant as well.
I became accustomed to Digester back before JAXB was part of Java (I'm really dating myself there), but I find myself continuing to use it because of the looser tie between the XML and the Java. I'm sure it's just my own lack of experience, but I find it hard to map XML to Java using JAXB unless the Java and the XML are really similar in structure -- that is, where elements map to classes and attributes map to properties. I've used Digester in cases where the Java and the XML look nothing alike and was pleased. Definitely not trying to say, "this is better than that," just saying, "I like this because..."