Myths and facts of "Java Everywhere"By Michael Yuan The big news from this year's JavaOne conference is "Java Everywhere". What exactly is "Java Everywhere"? It seems that there are a lot of confusions or even resistance from existing Java developers. I attempt to clarify some myths through a series of FAQs in this short article. You can post comments to the J2ME forum and I will read them. :) Please note that I do not work for Sun Microsystems. So, the opinions expressed here are only mine.
"Java Everywhere" is about world domination and new opportunities for developers. Interested readers can refer to my new book "Enterprise J2ME" (Coming out this fall from Prentice Hall) for more information. In the meanwhile, please continue the conversation in the Saloon. Return to Top |
|||||||||||||||||||||||||||
An Interview with Tim O'Reillyby Frank Carver JavaRanch:I'd like to introduce Tim O'Reilly. Tim O'Reilly is the founder and CEO of O'Reilly & Associates, thought by many to be the best computer book publisher in the world. O'Reilly also publishes online through the O'Reilly Network (www.oreillynet.com) and hosts conferences on technology topics. Tim is an activist for open source and open standards, and an opponent of software patents and other incursions of new intellectual property laws into the public domain. I've caught up with Tim as he grabs some lunch before hitting the podium to talk to the geeks and eggheads at British Telecom's sprawling Adastral Park research site. Let's start with a question on many of our minds here at the 'Ranch: How's the Java book market going, and in particular what about Kathy and Bert's "Head First Java"? Tim O'Reilly:Over the last few years, many Java books such as "Java in a Nutshell" have been big sellers for us, but we have seen a drop-off in the current economic situation. Programming books have been especially hard hit, with a lot of the book dollars moving to other subjects -- new operating systems like Windows XP and Mac OS X, and new application areas like digital photography. For example, Java was the #1 book category for one of our UK distributors last year, but the #16 area for them for the same period this year. "Head First Java" is an amazing book, but it's too soon to tell how much of an impact it will have. I'm sure that if we'd released it a couple years ago it would have been the #1 computer book bestseller, which would have put it on everyone's radar right away. Now it will just have to settle for being the #1 Java book :-), which means that it will take a bit longer for this approach to take over the world. What's exciting is that the Head First concept is applicable to far more than just Java. It's a whole new approach to teaching complex subjects in which mastering key concepts shapes subsequent learning. It can make very difficult subjects interesting and engaging, and can help even experienced developers to understand their tools more deeply. The question now, is what other areas can we give the "Head First" treatment. I'm open to suggestions! We're doing a lot of brainstorming with Kathy and Bert, because we believe they've come up with something really brilliant that can be used in so many ways. JavaRanch:How about other alternative approaches? The "hacks" series? Tim O'Reilly:Oh, the "Hacks" books are doing really well. "Google Hacks" was a number one seller for something like four months. Linux Server Hacks and Mac OS X Hacks have also been bestsellers. We have a new wave coming out this fall, including Amazon Hacks, EBay Hacks, Wireless Hacks, and Windows XP Hacks. For those of you who don't know them, the "hacks" books are full of short, fun, things to do, things that are both useful and catch the imagination. A book about Google might seem strange if you think of Google as just a web site. But it's not, its part of the new paradigm of software on the internet platform. You can't buy it or download it, but you probably use it every day, and there's a big difference between how beginners use it, and how experts use it. And that spread is what we thrive on. JavaRanch:Thanks. That leads quite neatly to another of my questions. How are you tackling the economic slowdown and the challenge of the internet? I've heard several people say that they don't buy tech books any more, it's all in Google! Tim O'Reilly:Of course there's been a change in buying patterns, but I couldn't say how much of that's due to the economy or the internet. Maybe in the long term we'll be able to look back and see trends. Reference books are down, but tutorials are still selling. People still like to have tutorials you can read in the bath. And people are always looking for succinct collections of expert knowledge -- it takes a lot of searching to accumulate the kind of depth that we have in our books. We are also at the forefront of technical publishing on the Internet, with both Safari and the O'Reilly Network. The O'Reilly Network is a free ad-supported network of online technical information sites, including www.oreillynet.com, xml.com, www.perl.com, and many others. More recently, we've started doing some "private label" online information sites partnering with corporate customers. The first of these, and most relevant to your audience, is java.net, which is sponsored by Sun. O'Reilly is producing the site, and developing all the content, as well as managing weblogs and other forms of user interaction. Over time, we may add some subscription-based sites to the O'Reilly Network as well. Safari (safari.oreilly.com) is a subscription-based reference library online, containing well over a thousand books from O'Reilly, Addison-Wesley, Prentice-Hall, Peachpit, Cisco Press, Macromedia Press, Adobe Press, and many other leading publishers. Interestingly enough, I got Pearson (the UK company that's the parent of all those non-O'Reilly imprints listed above) interested in partnering with us on Safari using an argument based on the ideas of "crossing the chasm". You start by gaining a small beach-head in one area, dominate that market, and then grow out to other markets. And the market we originally targeted to dominate was online publishing for Java. What I saw specifically was that if you had O'Reilly, Addison Wesley, and Prentice Hall books on one online site, you'd effectively have almost all the Java books that mattered. So we hoped to make this a must-have service for Java developers. Of course, it grew beyond that, and now, between O'Reilly and Pearson, Safari pretty much covers the computer tech books field. Right now the service mirrors the structure of existing books, but what we've created is a huge database of high quality technical content. Over time, it will become possible to offer services based on that content, services that go way beyond just reproducing the books online. JavaRanch:Wow, So what's your opinion on the advantages of the screen vs paper? Can you see publishing moving on to the internet completely? Tim O'Reilly:Well, there's no way that paper publishing will go away, at least not till we have "books" with "e-paper" that can be reloaded electronically with different texts. The user interface of the book is just too good for many types of task. That being said, though, what we really need to do is to ignore formats, and think about functions. A "book" is a form factor, but it covers a lot of different ground -- reference works, tutorials, entertainment. And translating those functions to a new medium will mean massive changes to how we think about electronic publishing. Most of the current eBook efforts are doomed to failure because all they do is try to reproduce what happens on the printed page. It's like claiming that the way to make a movie is to point a camera at a stage play. We know that's crazy. The medium has way more possibilities than that. We're already well beyond eBooks for many of the functions formerly performed by books. MapQuest and sites like it have put a lot of pressure on Atlases and maps; google and the entirety of the web put encyclopedias out of contention. Amazon has replaced the specialized "Books in Print" as the definitive source of bibliographic information. And can you deny that Everquest is successor to the fantasy novel? One that's presented in an immersive way that makes use of what the network platform has to offer. It makes the idea of an e-book reader with the straight text of "Lord of the Rings", or "Harry Potter" seem very weak in comparison. And I'll note that forward-looking authors like Tom Clancy not only write books, they produce movies and have companies to build computer games based on their characters and stories. George Lucas gets novelised versions of his movies, and has games like Star Wars Galaxies to boot. All of that is why I'm saying that eBooks per se are too limited a concept, and that what really interests me about Safari is how much more we can do once the technical information database it represents gets rich enough. JavaRanch:I think we're running out of time here, but have you got any general comments? Tim O'Reilly:If there's one thing you need to remember it's not to miss the important things by taking them for granted. A lot of people, even a lot of smart people, are stuck in the old paradigm of software as something that is delivered on a CD or on a personal computer. The real "killer apps" of the internet are not like that. For example, the fundamental paradigm shift represented by the internet is missed by many people in the open source software community. The killer apps of the internet are all built on top of Linux and use many other open source tools but are not themselves open source. A licence like the GPL which lays down what you must do when you distribute your software is simply never triggered. The code for Amazon is not open source, but it wouldn't be much use even if it was. The value in the system is not in the proprietary source code, but in the data and the network effect created by the large user base contributing to that data. The applications that are winning in the internet arena are the ones that make use of open source software to drive their costs down, but then harness the power of a collaborative community to help build their product on top of that open source base. They make money and survive not by selling software but by selling user benefits and encouraging the users to help their system grow. Every time you browse from one book to another, or write a review, or any of the things you can do with Amazon, you increase the quality and usefulness of their site. Every time you add a link on your web site you add to the power of Google. And this is a constant process. Microsoft may be on a three-year release cycle, but Amazon and Google are updated every day. JavaRanch:Thanks very much, Tim. I'll let you get back to your lunch, now! Tim O'Reilly:Thanks. Return to Top |
|||||||||||||||||||||||||||
An Interview with Andy Hunt and Dave Thomas, authors of The Pragmatic Programmerby Julia Reynolds The following interview was originally published in the Middle Tennessee Java User's Group (MTJUG) June 2001 newsletter. (Included here with permission.) In 1999 Andy Hunt and Dave Thomas published their common-sense guide to software development, The Pragmatic Programmer. MTJUG: What led you to write The Pragmatic Programmer? DAVE: When Andy and I first started programming together, it was obvious that we had a very compatible way of working. We'd both come up with many of the ideas that later made it into Pragmatic Programmer. During the next couple of years, we refined these into a pretty consistent set of practices. However, they were implicit: we hadn't written anything down--these were just things that we did every day. At the same time, we realized that much of this was new to others, and we were spending a lot of time explaining what we were doing every time we met a new project team. All this lead to the idea that maybe we should write down what we were doing. We thought it would be a pretty quick process, but in the end it took the two of us over a year. MTJUG: In your book you talk about the need for Pragmatic Programmers to invest regularly in their knowledge portfolios. You suggest a goal of learning a new language every year. What new languages are you interested in and would suggest others learn more about? ANDY: Ruby is the latest language that has piqued our interest (see www.ruby-lang.org). It combines the grace and elegance of Smalltalk with the sheer usefulness of Perl. I recommend it highly. DAVE: I'm planning to spend more time playing with Smalltalk this year. In particular, I want to get familiar with Squeak and the morphic interface. MTJUG: Which languages would be best to complement the knowledge portfolios of those of us specializing in Java development? ANDY: That's a tough question. For sheer mind expansion, you might want to look at a dynamically typed language. Ruby comes to mind, of course. Dylan and/or Self might be interesting just to see some other approaches inheritance and such. DAVE: I'd also suggest Java developers have a look at AspectJ, which is not so much a new language as an add-on to Java, allowing functionality to be spliced in to existing code. Again, it's a different way of looking at things. In general, look for languages with different philosophies to the ones you're using. Have a look at Haskell, or Self, or Smalltalk, and see what good ideas you can bring back to your existing environments. MTJUG: In Chapter 3, The Basic Tools, you suggest some very specific steps developers should take to master the tools of their trade. Of course, readers can't help but wonder which specific tools you favor in each of the toolsets you discuss. Specifically: What is your favorite text editor? (Obviously, readers of your book will know it's NOT Notepad!) ANDY: My favorite editor is vi, hands down. I like some of the features that Emacs has to offer, but I cannot stand the "emacs-pinky" syndrome. I actually use XEmacs in Viper mode, which gives me the best of both worlds -- vi key mappings in a XEmacs environment. DAVE: Andy of course has a quaint affection for vi, but there is clearly only one true editor, Emacs. I'm personally using XEmacs 21.4 for just about everything (e-mail, development, html and xml writing). Before that, I really liked the simplicity of Brief and Crisp. (Truth be told, I'm also pretty fluent in vi, but don't tell Andy :) Being able to create and manipulate text is key to our job: get good enough with whatever editor you use so that it becomes subconscious. You'll find that this makes things such as refactoring far, far easier. MTJUG: You emphatically advocate the use of Source Control for everything. What's your favorite Source Control System? DAVE: We've been using CVS for a while now: it's open source, distributed, multi-platform, and it doesn't enforce locks. It has its warts, but it really works very well in a multi-site, multi-checkin-a-day environment. MTJUG: What is your opinion of visual IDEs like JBuilder or NetBeans? ANDY: I don't do a lot with them, personally. For drag-and-drop to create a user interface, they're great, but for integrating into a sophisticated build environment, you may have some troubles. It also seems to be more difficult to integrate code generators and such into that kind of environment. DAVE: I have mixed opinions about them. On the one hand, I think they are great tools, vastly simplifying the development of complex applications. I know that half of the software we all use every day wouldn't exist if developers couldn't rely on the power of IDEs. At the same time, I find they have troubling aspects. One is that they dumb-down programming somewhat. If an IDE has a "create table" wizard, developers are fooled into thinking they are designing a database. If an IDE provides code to link fields to bean attributes, developers feel they're doing transactional programming. But behind the scenes, complex things are going on to support this simplicity. Sometimes you just _have_ to understand this complexity to make things work reliably. But the IDEs kind of give you the feeling that they're taking care of it all. We've seen this on recent projects, where developers used IDEs to write database access software that lacked any kind of transactional integrity. When we asked them about it, some of the developers didn't know what a transaction was. IDEs make things simple, but sometimes you need complexity. I'd rather see developers start off their careers by coding things themselves, and then cut over to using the wizards in an IDE once they understand what's really going on. MTJUG: You address unit testing in detail. Do you subscribe to the XP principle of coding the unit test first, before creating the module code? ANDY: I think it's a great idea, I've even done it on occasion :-). The nice part about this approach is that it forces you to consider the interface right off the bat ? and I mean *really* consider the interface, because you have to actually use the code you are about to write. Being forced to "eat your own dog food" this way suddenly makes you aware of "oh, it would be much handier for users of this code if I did it *this* way instead..." DAVE: I personally use a hybrid scheme. When I'm first writing a new class, I don't bother to do the XP 'write a test that fails' business, I just write the empty class definition. However, at that point I typically do drop into something approaching test first. I'll write the test framework for that class, and check that it all links together. Typically the first test will be simply constructing an object. Then I'll start writing tests and supporting code. I don't write strictly test first, because often in Java that's not possible. In particular, exception handling can really mess up testing: one line of code can potentially create three or four different exceptions, and I typically like to write test cases that check the handling of each. I find this isn't too dangerous: I can keep the need to write the four tests in my head while I'm coding. For more complex stuff I'll write placeholder tests: public void testMyNewFeature() { fail("test missing"); } If I forget to go back and fill them in I'm told the first time they run. I definitely feel that good unit testing is a skill that should be promoted more. Without a complete set of meaningful unit tests, altering code can become a crap shoot. And designing code to be tested really does load to a better structure. MTJUG: You mention eXtremeProgramming at several points in your book. Can you describe the development process you follow when working on project teams? ANDY: Well, it's different every time: sometimes subtly different, sometimes wildly. Alistair Cockburn's notion of "a methodology per project" is apt; to be truly pragmatic we must adapt as necessary to the people, culture and politics of each client individually. In fact, that's a big reason why we don't talk too much about any specific methodology in the book; the practices we advocate are appropriate (or not) independent of the methodology in use. If your team can embrace things like Pair Programming and it works for you, great! If you can't and it won't, then there are other approaches to take to ensure a common mental-map and community knowledge of the code. In general, though, we follow an agile approach (see www.agilealliance.org) to ensure that we deliver software of value that is fit for the business purpose, that can built and tested repeatably and reliably, and that honors basic architectural and design principles such as DRY and orthogonality (which gives you things like low coupling and high cohesion for free). DAVE: As Andy says, it varies, as we try to work with our clients, rather than dictate to them. Many teams (or their organizations) are not ready for revolutions, so we help introduce practices gradually, and in a way that addresses their more pressing problems first. Often this means getting the basics (such as source code control and a build system) in place first. We then try to introduce unit testing, incremental development, and other practices. XP has been wonderful at raising the general awareness for the need for process in software development, and for telling people that methodologies need not be Draconian. Return to Top |
|||||||||||||||||||||||||||
Working with Money in Javaby Thomas PaulNote: In all of the examples I use standard US notation of commas representing a numeric group separator and period as a decimal point. The number 1,000.00 is the number one thousand. Why can't my computer add?Sooner or later, everyone trying to calculate money in Java discovers that computers can't add. Take a look at this code:
This prints out $12,571,782.00, which is incorrect. The correct answer is $12,571,781.43. So what's the problem? Doesn't Java know how to add two numbers together? Actually, the problem is much older than Java and can be found in the IEEE 754 specification that defines how floating-point numbers work. As at least one software engineer has commented, "floating-point is designed to give you the wrong answer very quickly." This is not far from the truth.
What the heck is floating-point anyway?Floating-point numbers are actually made up of three different parts stored in a 32-bit field. The first bit is a sign bit. The next eight bits are the exponent and the remaining twenty-three bits are the significand. The exponent holds the highest power of 2 that is smaller than the number. The remainder is stored in the significand. Let's look at the number 1,000. The highest power of 2 less than 1,000 is 2 to the power of 9, which is 512. We add 127 to 9 (that is so we can store negative exponents without using a sign bit) and store that in the exponent. The remainder of 488 is stored in the significand. The significand is divided into two portions. In our example, the first 9 bits (the size of the exponent) represents the integral portion of the significand and the remaining 14 bits represents the decimal portion. Here is what the bit positions look like (I inserted a decimal point in the significand to show the two seperate sections):
The first part is the sign so we know we are dealing with a positive number. The second portion is the exponent. The bit pattern represents 136. If we subtract 127 we get 9, which is the exponent we expect. Since the exponent is 9, the first 9 bits of the significand represents the integral portion of our number. Converting that to decimal gives us 488. The remainder of the significand represents the decimal portion, which is zero. Now lets look at our problem number, 12,571,781.43. Converting that to float and displaying the bits gives us:
The sign is positive. The exponent is 150 which after subtracting 127 leaves us with 23. When we calculate 2 to the 23rd power we get 8,388,608. Subtract that from 12,571,781.43 and we are left with 4,183,173.43 that must be stored in the significand. The first 23 bits (because our exponent is 23) represents the integral portion. But wait! If we use 23 bits for the integral portion then we are left with nothing for the decimal portion. This means that the number 12,571,781.43 can only be stored as 12,571,781 in a float. Follow this example for the two values we are attempting to add in our test program above and you will see how we end up with the result we get. What if the exponent is greater than 23? In that case, the decimal number is calculated and then zeroes are appended to end for the missing digits. In other words we are losing precision in order to hold a larger number. The conclusion is that an int variable (31 significant bits) can actually store a larger whole number more accurately than a float variable (23 significant bits). A float can store a bigger number than an int because of the exponent but it can only hold about eight significant digits. In our test program above, we had nine significant digits in the two numbers we were adding and ten significant digits in the result so we ended up with the wrong answer.
So how do I calculate the CEO's stock options?We now know that unless we need to work with less than one million dollars that float is not going to work for us. So what do we do for large monetary calculations? There are at least two solutions that are commonly used. The first is to do everything using integral types. You will need to remember that "590" is really "$5.90" or your payroll system will be giving everyone big raises. You may, however, run into problems if you need to do percent calculations rounding to the nearest penny since ints don't support this type of calculation. You may want to write a class or two to help you out with this. There is, however, a better solution. Douglas Dunn ("Java Rules", p.235) has suggested that Java may be the first programming language where using a class instead of primitives to do monetary calculations may become the norm for mainstream business applications. That class is what the rest of this article will discuss.
BigDecimal to the Rescue!Here is the BigDecimal version of our test program:
This program prints out the correct answer, $12,571,781.43. In fact, the BigDecimal class can handle any number no matter how large it is (within the limitations of your computer's memory). How does it do it? BigDecimal stores numbers in an array. Each entry in the array represents a digit. The larger the number required, the larger the array that BigDecimal creates to hold the number. The scale (number of digits to the right of the decimal) is stored in an int. Running our test program with these statements will still produce the correct answer:
You will discover one problem in attempting to print these very large numbers using the NumberFormat class. The format method of the NumberFormat class converts BigDecimal to a double before formatting which limits us to only 16 significant digits. It would have been nice if the designers of the NumberFormat class had added a method to specifically handle BigDecimal.
Constructors of BigDecimalBigDecimal has four constructors but the one you will want to use most is the one that takes a String. If we ran our test program using the constructor that takes a double, we would still get the wrong answer if we used float constants:
The reason this doesn't work correctly is that the float constants will undergo loss of precision before they are sent to the constructor of the BigDecimal. Using the String constructor will always allow the BigDecimal to represent exactly the number you want.
Methods of BigDecimalBigDecimal supports add, subtract, multiply, and divide. The calculated scale for add and subtract is simply the larger scale of the two numbers you are working with. The calculated scale for multiply is the sum of the scale of the two numbers. The scale of the divide method is either the scale you specify in the method or the scale of the current BigDecimal object depending on which overloaded version of the BigDecimal you are using. The divide also requires that you specify a rounding method. ROUND_HALF_UP is the standard arithmetic rounding method used most often. Lets take a look at this code fragment:
This will print: 0.666666667. Since we specified a scale of 9, we get 9 digits after the decimal point. Since we specified "BigDecimal.ROUND_HALF_UP," we get the last digit mathematically rounded. BigDecimal supports the use of the compareTo method for comparing values. In most cases you will want to use the compareTo even for equals comparisons because the equals method considers two numbers with the exact same value but different scales to be not equal. In other words, the equals method considers 2, 2.0, 2.00, and 2.000 to be different numbers. The compareTo will consider all of them to be equal.
ConclusionI hope this has removed some of the mystery of the float primitives and has given you the desire to look into the BigDecimal class as a way to handle decimal arithmetic. The BigDecimal is the most accurate way to do arbitrary precision calculations. In most business applications, it is well worth the cost of the overhead of working with objects for the added accuracy you get with the BigDecimal class.
ReferencesA lot of the information for this article was derived from the book, "Java Rules" by Douglas Dunn. This is a great book that should be owned by everyone who wants to understand the workings of the Java language. Ilja Preuss pointed out an article dealing with formatting BigDecimal numbers. As I mentioned above, the NumberFormat class doesn't do a good job with BigDecimal. The article from Tech-Tips provides at least one solution. Jason Menard wrote a nine horseshoe review of a book entitled, "Java Number Cruncher" by Ronald Mak. The book deals with number issues in Java including the problem of dealing with the IEEE 754 specification. Return to Top |
|||||||||||||||||||||||||||
Touring the Commons - part 1by Jason Menard (jason@javaranch.com) This is the first in a three part series discussing elements of the Jakarta Commons project. The first part discusses the Commons BeanUtils package, the second part will discuss the Commons Digester package, and the final part will demonstrate using these packages together to build a framework for dynamically generating data transfer objects. IntroductionThe Jakarta Commons project is a warehouse of reusable Java components. Two very useful components in Commons are BeanUtils and Digester. Digester, which I will discuss in the second part of this series, is a set of classes that facilitate the easy mapping of XML to a Java object. BeanUtils, provides easy wrappers around the Java introspection and reflection APIs, facilitating the simple manipulation of JavaBeans and the creation of dynamically generated JavaBeans. JavaBeansWhat is a JavaBean? I'll refer you to the Sun JavaBeans API Specification for all the down-and-dirty details, but for our purposes there are a few important things to highlight:
Here is an example of a simple JavaBean representing some business class called User, presumably the user of some system we are working on:
If you take a glimpse at the User class you will see it has the common attributes that we associate with JavaBeans. It has getXxx() and setXxx() methods for its properties, and it has the default constructor. Additionally we threw in a couple of business methods that might exist to save the objects state in the database. The PropertyUtils ClassThe Commons BeanUtils component provides a class called PropertyUtils that supplies methods for manipulating JavaBeans such as our User class. Using PropertyUtils to call the accessor and mutator methods would look something like this:
But what's the point? Why not just call the appropriate accessors or mutators? That's a fair question if we know exactly what type of object we are dealing with in advance. That may not always be the case however. Often times in applications we use Data Transfer Objects (DTO) to represent the state of an object in a compact format suitable for serializing and transmitting over a network. Often times a DTO will look a lot like a business object in terms of the properties it exposes, yet it will not possess any business methods. A DTO for the User class might be something like the following:
When we are using DTOs, often we are copying data back and forth between the DTO and the business object. As this is the case, we might write a method or two to facilitate this copying. Normally we might have to write multiple methods depending on the direction we are copying our data - from DTO to business object, or from business object to DTO. On top of that, we would have to write these transfer methods for every DTO and business object in our system. Using PropertyUtils, we can get away with writing just one method.
Now using the above method, we could call either copyProperties(user, userDTO) or copyProperties(userDTO, user) as appropriate to achieve the desired results. Recognizing how amazingly useful a method such as the above is, there just so happens to be a method in PropertyUtils already in place for doing just this. Coincidentally, the method is :
To copy the properties from a User object "user", to a UserDTO object "userDTO", we can use the following single line of code:
That sure beats writing a bunch of code calling several get and set methods, doesn't it? One thing you may have noticed is that up to this point we have only referred to simple properties, via methods such as PropertyUtils.getSimpleProperty(). A simple property is a property with a single value. Java primitives and Strings are just a couple of examples of simple properties. That may cover you in most situations, but PropertyUtils also offers methods for handling other types of properties. Specifically, there are additional methods for dealing with indexed properties, mapped properties, and nested properties. Indexed properties maintain an ordered collection of objects that are accessed individually by an integer index value. Arrays are the obvious example, but the BeanUtils package also handles indexed properties that are based on an underlying java.util.List. If a bean "myBean" has a property:
Then we might access this property in the following manner:
Which is analogous to:
Mapped properties are based on an underlying java.util.Map. A String key retrieves the value of a mapped property. If a bean "myBean" has a property:
We could access this property using PropertyUtils like so:
This is somewhat analogous to:
If a property of a bean is itself a JavaBean, that properties of that JavaBean are known as nested properties. A nested property may also be simple, indexed, mapped, or even further nested. Nested properties are accessed using a dotted notation that should be familiar to us. If we have a bean "myBean" with the following property:
We could access the simple property "name" of the property "user" like this:
Accessing a nested property of a mapped property:
Accessing a nested property of an indexed property:
PropertyUtils also provides generic getProperty() and setProperty() methods that may be used to manipulate any property, whether it is simple, indexed or mapped, and regardless of how deeply nested. For example:
Dynamic BeansWhile the methods described above for dealing with existing beans are certainly very handy, the meat of this package comes in the form of dynamically generated beans, or "DynaBeans". If you've ever used dynamic action forms in Struts, then you have used DynaBeans. The BeanUtils package has two interfaces for handling dynamic beans: the DynaBean interface, and the DynaClass interface. Concrete implementations of these interfaces are provided in the form of BasicDynaBean and BasicDynaClass classes. Like standard JavaBeans, DynaBeans have a set of properties that may be accessed or changed. Going back to our earlier example of the User bean, let's say we have a DynaBean with the same set of properties called "user". This is how we would go about getting and setting our properties:
It can't get much easier than that. In addition to the above methods for manipulating simple properties, an object implementing the DynaBean interface must also provide the following methods for manipulating indexed and mapped properties:
In order to generate our own DynaBean classes, we must first provide an implementation of DynaClass. A DynaClass provides the same basic functionality as java.lang.Class for classes that implement the DynaBean interface. It is in a concrete implementation of DynaClass where we must specify the properties of associated DynaBeans, and it is this DynaClass implementation that generates new instances of a DynaBean with the specified properties. The set of properties a DynaBean has may be described by an array of DynaProperty objects. A DynaProperty has name and type attributes. Instantiating a DynaProperty that is equivalent to the User name property from our example would be done like this:
A DynaProperty array describing all the attributes from our User bean:
Getting back to the DynaClass interface, if we take a look at BasicDynaClass we see the following constructor:
The name parameter is the name of this DynaBean class, and the properties parameter describes the properties our DynaBean will have. The dynaBeanClass parameter is the class of the implementation of DynaBean we are using. If we use null for the dynaBeanClass parameter, this DynaClass will produce new instances of DynaBeans of type BasicDynaClass. From this information, and with our previously constructed array of DynaProperty objects, we can now construct our DynaClass.
Let's now put it all together to retrieve and use a new instance of our user DynaBean.
The BeanUtils ClassThe BeanUtils class has several static methods for manipulating DynaBeans in much the same way that the PropertyUtils class manipulates standard JavaBeans. Methods provided to get and copy properties are the same as in PropertyUtils, however the only mutator provided is the generic setProperty() method. With this in mind, we can copy values from our user DynaBean to or from an instance of the User object we discussed in the first section.
One additional method of note in BeanUtils allows the copy of a set of mapped properties into a DynaBean, using the populate() method. If the map has a key that corresponds to the name of a DynaBean property, it will attempt to copy it. Let's take a look at the following example:
Type conversion is handled behind the scenes using methods defined in a class called ConvertUtils. You may write your own converter by implementing the Converter interface and then calling the ConvertUtils.register() method in order to register your new Converter. BeanUtils In ActionLet's do something useful with what we've learned. Here's a method that will take a HttpServletRequest object and return a populated DynaBean dynamically generated from the names and values of the request parameters.
ConclusionHopefully I've demonstrated just how handy this package can be. Be sure to check out the API documentation for more information, particularly the documentation for the org.apache.commons.beanutils package. This is just one of many useful components of the Jakarta Commons project, and next month we will take a look at another. ResourcesPlease feel free to email me with any questions or comments concerning this article. Return to Top |
|||||||||||||||||||||||||||
Small and Simple Web Applications - the Friki Way (Part 4)Frank Carver, July 2003AbstractThis article is the fourth of a series which laments the bloated and unmaintainable state of so many J2EE web applications and looks at ways to keep web applications small, simple and flexible. The series uses the author's Friki software as a case study, and discusses ways to design and build a powerful, flexible and usable web application in less space than a typical gif image. This article carries on working through the user requirements. On the way we'll start to extend our build system to make a deployable web application. IntroductionIf you've read the first, second and third articles, you should be aware that the aim of this project is to develop a small, simple and understandable "Wiki" (editable web site) application. We've considered and decided to defer the relatively heavy decision of how to store and retrieve pages by introducing a Java interface, decided on and implemented a simple "template" system to display pages, and are building a supporting test suite and an automated build script as we go along. First, let's recap what our "customer" wants, and what we have got so far:
What do we write next?In the previous article I introduced the idea of "picking off" the easiest thing to test. Carrying on with this we now need to make a guess at which remaining story is the one to go for. Stories one and four still look like they need a server, and story five needs a repository. Looks like story three is the next easiest. Interestingly, it looks much easier now that we have got story two working. So let's get started. Second task: links to nonexistent pages will be marked with a '?'As usual, we start by adding a new test. This time, though, there's no need to start a whole new test class. We can just add to the existing "LinkTest" and see how far we get. We want page references to missing pages to be identified by a '?' which (when clicked) brings up an "edit" page to create the new page. LinkTest.java package tests; import junit.framework.*; import friki.PageFormatter; public class LinkTest extends TestCase { PageFormatter formatter; public void setUp() { formatter = new PageFormatter(); } public void testEmpty() { assertEquals("", formatter.format("")); } public void testNonLink() { assertEquals("hello", formatter.format("hello")); } public void testEmbeddedLinkSymbol() { assertEquals("friki@javaranch.com", formatter.format("friki@javaranch.com")); } public void testLink() { assertEquals("<a href='view?hello'>hello</a>", formatter.format("@hello")); } public void testLinkInPage() { assertEquals("You say <a href='view?hello'>hello</a>, I say goodbye.", formatter.format("You say @hello, I say goodbye.")); } public void testMissingLink() { assertEquals("goodbye<a href='edit?goodbye'>?</a>", formatter.format("@goodbye")); } } Compile and run this by typing "ant". Does it work? Of course not. We have no code for it. What we get back is the HTML as if it is a known page. What we need to do, is to add some code which can tell the difference between known and unknown pages. Before we hit the keyboard, let's think a little. Even though this is still a very small project, do we have anything which we can re-use? In the very first installment of this series, we created an interface: PageRepository.java package friki; import java.util.Iterator; public interface PageRepository { public Page get(String name); public void put(String name, Page page); public boolean contains(String name); public Iterator matchingPageNames(String pattern); } That "contains" method looks like just what we need. Let's create the smallest "cheating" class we can, and see if it helps. InMemoryPageRepository.java package friki; import java.util.Iterator; public class InMemoryPageRepository implements PageRepository { public boolean contains(String name) { return !"goodbye".equals(name); } public Page get(String name) { return null; } public void put(String name, Page page) {} public Iterator matchingPageNames(String pattern) { return null; } } It won't compile, we need a Page class. Before we leap to create one, let's stop and think for a bit again. Why do we need a Page class at this point? It's not for the method we want to use, but for some of the others - ones that we've made dummy implementations for. I can't shake the feeling that there's something wrong with making an empty class just to satisfy an empty method. Is there a better way? Luckily, there is. Remember when I said in part 2 "This interface may change or even disappear before any code is released"? Well here's just such a change. Extract the "contains" method to its own interface: Container.java package friki; public interface Container { public boolean contains(String name); } PageRepository.java package friki; import java.util.Iterator; public interface PageRepository extends Container { public Page get(String name); public void put(String name, Page page); public Iterator matchingPageNames(String pattern); } That's much better. Now we can get rid of those empty methods from our "in-memory repository", because all it needs to be is an "in-memory container": InMemoryContainer.java package friki; public class InMemoryContainer implements Container { public boolean contains(String name) { return !"goodbye".equals(name); } } It now all compiles, and it's neater. That's more progress. But it still doesn't make that failing test pass. We now need to use our new container in the application code. If you look back up to the test code you'll see that the formatter is responsible for generating the links, and so that's the object which needs to know about presence or absence of pages. For the moment, let's just pass our container into the formatter constructor: LinkTest.java package tests; import junit.framework.*; import friki.PageFormatter; import friki.Container; public class LinkTest extends TestCase { PageFormatter formatter; public void setUp() { InMemoryContainer container = new InMemoryContainer(); formatter = new PageFormatter(container); } ... } Looks good. But we need to update the PageFormatter to use the container: PageFormatter.java package friki; import java.text.CharacterIterator; import java.text.StringCharacterIterator; public class PageFormatter { private char symbol = '@'; private Container container; public PageFormatter(Container container) { this.container = container; } private String makeLink(String name) { if (container.contains(name)) { return "<a href='view?" + name + "'>" + name + "</a>"; } else { return name + "<a href='edit?" + name + "'>?</a>"; } } ... } Run the tests: [junit] Tests run: 10, Failures: 0, Errors: 0, Time elapsed: 0.078 sec Excellent. We're still "cheating", though. Let's add another test to point this out: public void testMissingLink2() { assertEquals("whatever<a href='edit?whatever'>?</a>", formatter.format("@whatever")); } It fails, of course. It's time to make that container class do some work. There's no need to do more work than necessary, though, especially when there are system classes to help: InMemoryContainer.java package friki; public class InMemoryContainer extends java.util.HashMap implements Container { public boolean contains(String name) { return super.containsKey(name); } } LinkTest.java package tests; import junit.framework.*; import friki.PageFormatter; import friki.Container; public class LinkTest extends TestCase { PageFormatter formatter; public void setUp() { InMemoryContainer container = new InMemoryContainer(); formatter = new PageFormatter(container); } ... } Run the tests: [junit] Tests run: 11, Failures: 1, Errors: 0, Time elapsed: 0.125 sec The tests still don't work. Can you tell why? The trick is to look in the test log, and see what failed: Testcase: testLinkInPage took 0.016 sec FAILED expected:<...<a href='view?hello'>hello...> but was: <...hello<a href='edit?hello'>?...> ... Aha! Our new test now works, but in making it work we have broken one of the existing tests. Here we begin to see the huge value of keeping our test cases for old features, and re-running them every time. If we look at the tests, we see that the old test just assumes that the page "hello" is present. But our new InMemoryContainer starts off empty, so there is no page "hello". The code is all doing what it should; we just need to tell the new container that we have a page "hello". LinkTest.java package tests; import junit.framework.*; import friki.PageFormatter; import friki.Container; public class LinkTest extends TestCase { PageFormatter formatter; public void setUp() { InMemoryContainer container = new InMemoryContainer(); container.put("hello", "some stuff"); formatter = new PageFormatter(container); } ... } Run the tests: [junit] Tests run: 11, Failures: 0, Errors: 0, Time elapsed: 0.078 sec Cool.That's another feature done. Feel free to add more tests if you are not sure of anything. The gurus say "keep adding tests until fear turns to boredom" Let's make war!If we ever want to have an application we can just "drop in" to a servlet container, we need to make a deployable "war" file. I won't go in to a lot of detail on the structure and contents of a war file right now; I suggest you look around the internet a bit in preparation for the next installment. This time, however, all we are concerned about is what to do with our freshly baked, tested, class files. Before I describe how to do this, I'll take a few moments to describe how not to do it. Do you use an IDE (integrated development environment) which has buttons or menus for this sort of thing? It's a great temptation to use IDE features, but in this case I feel strongly that it would be a mistake. We want the complete build-test-package-deploy cycle to be seamless, simple and quick. We already use Ant for compilation and testing, and I suggest that Ant is good for this too. When we have eventually finished, I'm expecting to be able to just type "ant" to compile and completely test the code, build a web application and deploy it to a running server. Stopping half-way through to click some buttons or menu choices seems a clumsy way to do it. If you have been paying attention, you should have guessed that I would recommend Ant for this. What you may not have been able to predict is that even though Ant includes a built-in "war" task, I don't recommend that you use it! The Ant "war" task allows you to combine physically separated resources into a single war file. It does this by requiring you to specify where to get each of the main categories of information in the war file. So you tell it separately where your classes are, where your "web.xml" file is and so on. While this is a useful facility if you want to build a war file from files scattered across a file system, our ant build is not like that. We have control of where our files go. The final nail is that some versions of the "war" task have problems, such as creating the important "WEB-INF" directory as the non-standard "web-inf". For most day-to-day purposes I recommend using the much simpler "jar" task instead. Use the ant "copy" task to make sure all our resources are laid out under some directory as they would be in a war file, then scoop the whole lot up using "jar". Add the following to "build.xml": build.xml <project name="friki" default="build" basedir="."> ... <target name="build-war"> <mkdir dir='build/war/WEB-INF/classes'/> <copy todir='build/war/WEB-INF/classes'> <fileset dir='build/delivery/classes'/> </copy> <jar jarfile='frikidemo.war'> <fileset dir="build/war"/> </jar> </target> <target name="build" depends="compile,test,build-war"/> </project> Now we can run this and look at the generated "frikidemo.war". It should be about 4K bytes. If you wish, you can use something like WinZip to see what's inside, and check that all our class files are in there. How are We Doing?We still haven't made a Wiki yet! But we have completed another of our user goals, and have built on our ant-scripting efforts to automatically produce our first web application "war" file. We've also seen the benefits of growing our regression test suite as we go along. Next session we will attack some more customer goals, and we really will produce an application which can be deployed to a web server and actually do something. Return to Top |
|||||||||||||||||||||||||||
A Poem on Java 1.5 - Tigerby Joshua BlochJoshua Bloch recited the following poem, which he also wrote, at the conclusion of the "TS-3072: Forthcoming Java Programming Language Features" 2003 JavaOne converence session. (Included here with permission.) Tiger, Tiger Burning Bright Like a geek who works all night What new-fangled bit or byte Could ease the hacker's weary plight? To the most despised cast We'll bid a fond farewell at last With generics' burning spear The need for cast will disappear While Iterators have their uses They sometimes strangle us like nooses With enhanced-for's deadly ray Iterator's kept at bay When from collections ints are drawn Wrapper classes make us mourn When Tiger comes, we'll shed no tears We'll autobox them in the ears The int-enum will soon be gone like a foe we've known too long With typesafe-enum's mighty power Our foe will bother us no more And from the constant interface we shall inherit no disgrace With static import at our side, our joy will be unqualified And as for noble metadata I'll have to sing its praises later Its uses are so numerous To give their due, I'd miss the bus Tiger, Tiger Burning Bright Like a geek who works all night What new-fangled bit or byte Could ease the hacker's weary plight? (With apologies to William Blake) Return to Top |
|||||||||||||||||||||||||||
Mosey on in and pull up a stool. The JavaRanch Big Moose Saloon is the place to get your Java questions answered. Our bartenders keep the peace, and folks are pretty friendly anyways, so don't be shy! We pulled one out from the deep past for this inaugural column. Over in The Java In General (Beginner) Forum, JavaRanch's own Frank Carver did a heck of a job tellin' folks about making a Singleton in Java. Following is an excerpt from the original forum thread. Question: What's a Singleton?Answer: A singleton is an object of which there may only ever be a single instance. (*) You can make your own class act like a singleton, simply by only creating a single instance. But this relies on every programmer who uses your code knowing that there is only supposed to be one instance of the class, which is dangerous. A better solution is to write the class in a way which prevents a casual programmer from creating more than one instance. This is where the Singleton pattern and its associated Java idioms help you. Lets start with a simple class: public class Something { private String content = "empty"; public void setContent(String content) { this.contemt = content; } public String getContent() { return content; } } The most obvious way for a programmer to try to create an instance of a class is to call its constructor, so we need to prevent this. If we just fail to provide a constructor, Java assumes that there is a "default constructor" taking no arguments which just creates an instance of the class; not what we need! The Java "trick" for this is to have a constructor, but make it private so no other classes may call it. public class Something { private String content; private Something() { content = "empty"; } public void setContent(String content) { this.contemt = content; } public String getContent() { return content; } } Now that we have no constructor, we need to make a way for people to create a single instance of the class. Typically this is done by provding a static method which creates an instance, but will create only one. If it is called again, it just returns the same instance that it created the first time. public class Something { private static Something instance = null; private String content; private Something() { content = "empty"; } public static Something getInstance() { if (instance == null) { instance = new Something(); } return instance; } public void setContent(String content) { this.contemt = content; } public String getContent() { return content; } } Now the code is almost complete. The last thing to remember is that Java is a multi-threaded language in which many things can be happening "at once". If two threads were to call getInstance at the same time, then our class might occasionally create two instances, which would be wrong and very hard to test. So we make use of Java's built-in synchronization mechanism to make sure that only one thread can call getInstance at any one time. So the final singleton class looks like: public class Something { private static Something instance = null; private String content; private Something() { content = "empty"; } public synchronized static Something getInstance() { if (instance == null) { instance = new Something(); } return instance; } public void setContent(String content) { this.contemt = content; } public String getContent() { return content; } } I hope this helps. (*) The Singleton pattern actually allows for a specified number of instances, but singletons are harly ever used for any number other than one. Return to Top |
|||||||||||||||||||||||||||
Programming Diversions Puzzleby Jason Menard This month's puzzle is courtesy of Jim Yingst. Maze Solver Given an input ascii representation of a maze, write a program to find and display a path from the start point of the maze to the end point of the maze. The output should be a textual representation of the path through the maze from start to finish. It is suggested to use a series of '.' (period) symbols to indicate the path through the maze. You may discuss this puzzle and post your solutions in the Programming Diversions forum. Notes:
Maze #1 +++++++++++++++ + + + + + + + + + + + + +++ +++++ + + O + +++ X +++ +++++ +++ + + +++ + + + + + + +++++++++++++++ Maze #2 +++++++++++++++++++++++++ + + + + +++++++ + + +++++++++ + + + + + + + + +++++ +++ + +++ +++ + + + + + + + + + + + +++ + + + + +++ +++ + + + + +O + + + +X + + + +++++ + + +++++ +++++++ + + + + + + +++++ + +++ + + + + +++ + + + + + + + + + + +++ + +++++ + +++++ +++ + + + + +++++++++++++++++++++++++
Return to Top |
|||||||||||||||||||||||||||
Return to Top |
|||||||||||||||||||||||||||
Return to Top |
|||||||||||||||||||||||||||
July
Scheduled Book Promotions :
Return to Top |