Matt RaibleMatt Raible is a Web Developer and Java Champion. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.
You searched this site for "appfuse". 771 entries found.

You can also try this same search on Google.

log.debug vs. logger.debug - which do you prefer?

This is probably a bit of a religious debate, but it can't hurt to ask. Do you prefer to use log.debug() or logger.debug() in your Java classes? A fair amount of open source projects use Commons Logging and many of them seem to use logger. Personally, I prefer log (esp. b/c it's shorter), but I'm willing to change based on what the community (particularly AppFuse users) prefer.

Here's another tip I learned today. I typically declare a log variable for each class, such as this one in BaseAction.java:

    protected static Log log = LogFactory.getLog(BaseAction.class);

A better design can be found in Spring's DaoSupport classes. They have a logger variable that all its subclasses can use - eliminating the need to initialize a log variable in each class.

    protected final Log logger = LogFactory.getLog(getClass());

Obviously this is cleaner than AppFuse's current design - so I'll be changing it for 1.6. Any reasons why I shouldn't?

Posted in Java at Aug 16 2004, 09:47:58 PM MDT 21 Comments

August Status after two weeks

It's been almost 2 weeks since I set out to make this a month to remember. My progress so far? I'm behind. I put in 60 hours in front of the computer last week and 70 this week. Here's the break down of where I spent my time:

  • Current Client: 80 hours
  • Raible Designs: 27 hours
  • AppFuse: 7 hours
  • Spring Live: 16 hours

You can see where the problem lies - in the time spent on Raible Designs stuff. This time was mostly due to fiddling with the new monitor and 17 hours on Monday trying to get Radeon DVI cards working on Linux. I guess I like thumping my head against the wall. The time I spent on Spring Live was doing editing for Chapter 6 and coding for Chapter 7. I was hoping to have Chapter 7 done by today, but that's not gonna happen - so I'll be working tomorrow and taking off Monday to try and it finish up.

My original goals for this month were to finish Spring Live and release AppFuse 1.6. For Spring Live, I still have to write 2 more Chapters after Chapter 7. That's 1 chapter next week and 1 chapter the week after. Yeah right. Chapter 6 took me the entire month of July and Chapter 7 has already taken me 2 weeks. I'm still hopeful I can come close to pulling it off. The problem is that I never account for editing - and that seems to take a few hours per week once I've turned a chapter in. Worst case, Spring Live 1.0 will be released in late September. This might happen anyways since the editing for the ERP took 3 weeks and I'd like to fix all the issues found in the first 5 chapters. Fixing issues will probably take a day since I need to setup JIRA, enter all the issues, and then proceed to make sure they're fixed.

As for AppFuse 1.6, I think the WebWork integration should only take a couple of days. But that's 2 solid days. The other big issues involve a lot of XDoclet hacking and modifying, so that's probably another day there. Give it another day for various other bugs and one more for documentation updates/tutorial writing - and I'm up to 5 days. Yet this is still possible too. My current contract is scheduled to end when the baby is born, but I think I'm going to end it on Friday, August 27th. This gives me the next week to work on AppFuse - if the baby doesn't come. The baby is due on Friday, September 3rd.

The interesting thing about this week over the last was it was a coding week for Spring Live. When I write code, I prefer to have no deadlines - so I do it at night. If I did it in the morning, I'd have to quit coding around 8 and start my day job. By doing it at night, I'm pretty much giving myself the whole night to get stuff done. I've gone to bed b/w 3 and 4 every night this week. My problem is that I then sleep in until 9 or so. When I write, I find it's easier to get up in the morning, with a clear head and go to it. It's going to be tough making the transition from going to bed at 4 to getting up at 4. The good news is that I'm not just letting my body go to shit like like last time, I've actually been exercising. I feel great, but my fingers are starting to cramp from typing so much.

NOTE: If Julie goes into labor anytime in the next 3 weeks, all bets are off. ;-)

Posted in General at Aug 14 2004, 12:36:29 PM MDT 4 Comments

This site crashes a lot

It's plagued me before, and now it's back again. When I go to sleep at night, this site crashes. I've been up until 4 lately and it still seems to wait until I fall asleep. In fact, my 500 page is my top referrer this month. That's not good. The problem is probably not Roller - since JRoller seems to stay up and humming. Although it does die, I do have somewhere around 30 open database connections.

The truth is I need to run a profiler and figure out what's wrong. Unfortunately, I don't have the time and it doesn't really bother me that much. I just end up with a whole bunch of "your site is down" e-mails every morning when I wake up. Hopefully I can fix it soon. I've been telling people I'll have more time when the baby comes. They think I'm kidding - but I think it's true. My job will be handling Abbie while Julie nurtures the new baby. Abbie sleeps 12 hours at night, and 2-3 hours in the afternoon. I sleep 4-5 hours a night. That's a lot of time to get stuff done. ;-)

Posted in General at Aug 13 2004, 11:12:03 AM MDT 48 Comments

[DJUG] The Google Guys

I'm sitting at the Denver JUG meeting and Joshua Bloch and Neal Gafter just finished a talk on "Java Puzzlers". I didn't show up until halfway through - but it was still a great half hour. They had a bunch of slides with problems that had seemingly easy answers. They'd both have a good dialog about their proposed answers - and then asked the crowd what they thought. The problems were mostly due to dumb (but real world mistakes) - the kind of thing you'd slap your fellow programmer for writing. These guys are definitely fun to listen to - next up is Tiger and what's new in 1.5 (I thought it was 5.0?). Boy, it's a full room tonight - I'd bet there's around 120-150 people here.

Taming the Tiger

Major theme of "JDK 5" is ease of development with features like generics, for-each loop, autoboxing/unboxing, enums, varargs, static imports and annotations. It's designed to make programs clearer, shorter and safer by providing linguistic support for commong idioms. Sidenote: Joshua said that Neal wrote the compiler - and they've basically made it more rigorous so it writes the boilerplate code for you. New features do no sacrifice compatibility or compromise the spirit of the language. Neal has been using these features for a couple of years now and he says he's really enjoyed them.

Goal of this talk is to make it easy for us to understand JDK 5 so we can start using it in our development. Let's look at the different features of 5.0.

Generics, For-Each and Autoboxing/unboxing

Generics allow you to specify the element type of collection. Rather than specifying a List - you specify it's contents - i.e. String. It's basically stronger typing with less typing which enforces the specification at compile time. For example, the following code using the new for-each syntax to iterate through a list of TimerTasks in a collection. Notice the lack of casting and easy-to-read loop syntax.

void cancellAll(Collection<TimerTask> c) {
    for (TimerTask task : c) {
        task.cancel();
    }
}

Bytecode is the same as it is in 1.4 - 5.0 merely converts the code for you. One question that these guys have heard a lot is why ":" rather than "in". The answer is twofold - because "in" is already a keyword (for example, System.in) and they didn't want to introduce a new keyword. Because 'in' is an identifier that is already in widespread use, and thus they could not make it a keyword without serious impact. Only new keyword in JDK 5 is enum.

The Collection Interface has been Generified. All existing code should still work, but you can also use the new stuff if you like. I haven't listened much to what's new in 5.0 - but this is wicked cool. You might say it sucks because now you end up with strongly typed stuff, but at least you won't have any more ClassCastExceptions.

  • autoboxing: automatic conversion from int to Integer (or from double to Double, etc.)
  • unboxing: automatic conversion from Integer to int

For example, you can now easily do the following:

Integer i = new Integer(5);
Map map = new HashMap();
map.put("result", i+1);

Notice that the Integer type is converted to an int for the addition, and then back to an Integer when it gets put into the Map. Cool, huh?

JDK 5 also simplifies reflection. Class Class has been generified - Class literal Foo.class is of type Class<Foo>. This enables compile-time type-safe reflection w/o casting. The following used to return an Object and required casting.

Foo foo = Foo.class.newInstance();

This enables strongly typed static factories. I wonder if this can be used with Spring so you don't have to cast a bean when grabbing it from the ApplicationContext?

When should you use Generics? Any time you can - unless you need to run on a pre-5.0 VM. The extra effor in generifying code is worth it - especially b/c of increased clarity and type safety.

When to use for-each loop? Any time you can b/c it really beautifies code and makes it much easier to write. It's probably the smallest new feature in 5.0, but likely to be a favorite. You can't use for-each for these cases:

  • Removing elements as you traverse a collection (b/c there's no iterator)
  • Modifying the current slot in an array or list (b/c the index is hidden)
  • Iterating over multiple collections or arrays

The lack of an index seems to rub the crowd wrong. Joshua and Neal's response is they tried to design something very simple that would capture 80% of usage. If you need an index, just use the old for loop - it ain't that hard; we've been doing it for years!

If you want to use for-each in your APIs - i.e. if you're writing a framework, a class should implement the new Iterable class.

When should you use autoboxing? When there is an impedance mismatch b/w reference types and primitives. Not appropriate for scientific computing. An Integer is not a substitute for an int. It simply hides the distinction between wrappers and primitives. A null unboxes by returning a NullPointerException. They did consider setting it to the primitive's default, but the community voted 50-1 to for NPE.

Enums

JDK 5 includes linguistic support for enumerated types. Advanced OO features include the ability to add methods and fields to enums. Much clearer, safer, more powerful than existing alternatives (i.e. int enums).

enum Season { WINTER, SPRING, SUMMER, FALL }

I just noticed that it's boiling in here - A/C must be out again in the auditorium. It's 8:20 right now, I hope this is over soon, I can feel sweat beading on my forehead.

Enums are Comparable and Serializable. Enum constants should be named similar to constants. Enums are basically a new type of class. As far as I can tell, I have no use for Enums in my code. There's lots of gasps from the crowd as Joshua is describing the features of Enums (i.e. constant-specific methods). Sure it looks cool, but I still don't think I have a use for it. Maybe framework developers will find this useful. BTW, there's two high-performance collection classes: EnumSet (bit-vector) and EnumMap (array). EnumSet replaces traditional bit-flags: i.e. EnumSet.of(Style.BOLD, Style.ITALIC).

When should you use Enums?

  • Natural enumerated types: days of week, phases of moon, seasons
  • Other sets where you knkow all possible values: choices on menus, rounding modes, command line flags
  • As a replacement for flags (EnumSet)

Quote of the night: "It's extraordinarily rare that you'll need to cast when programming with JDK 5".

Varargs

A method that takes an arbitrary number of values requires you to create an array. Varargs automates and hides the process. James Gosling contributed the ... syntax. Varargs always has to be the last parameter. MessageFormat.format has been retrofitted with varargs in JDK 5:

public static String format(String pattern, Object... arguments);

String result = MessageFormat.format("At {1,time} on {1,date}, there was {2} on planet "
                                     + "{0,number,integer}.", 7, new Date(),
                                     "a disturbance in the Force");

Reflection is now much easier with Varargs - so you can call c.getMethod("test").invoke(c.newInstance()) instead of c.getMethod("test", new Object[0]).invoke(c.newInstance(), new Object[0])).

When should you use Varargs?

  • If you're designing your own APIs - use it sparingly.
  • Only when the benefit is compelling. Don't overload a varargs method.
  • In clients, when the API supports them: reflection, message formatting, printf

Static Imports

Clients must qualify static members with class name (Math.PI). To avoid this, some programmers put constants in an interface and implement it. BAD - "Constant Interface Antipattern". They've made this mistake in the JDK - java.util.jar has this pattern. Static import allows unqualified access to static member w/o extending a type. All static fields, methods, etc. will be available for your class using static imports. For example:

import static java.lang.Math.*;
r = cos(PI * theta);

When should you use Static Imports?

  • Very sparingly - overuse makes programs unreadable.
  • Only use it when tempted to abuse inheritence.

Metadata

Decorates programs with additional information. Annotations don't directly affect program semantics. They *can* affect treatment by tools and libraries. Can be read from: source, class files, or reflectively. Ad hoc examples: transient, @deprecated. Tiger provides a general purpose metadata facility.

Why Metadata?

  • Many APIs require a fair amount of boilerplate - i.e. JAX-RPC.
  • Many APIs require "side files" to be maintained. Examples: BeanInfo class, deployment descriptor.
  • Many APIs use naming patterns, i.e. JUnit.

Metadata encourages a declarative programming style - tell a computer what to do, now how to do it. Annotation Type Declarations are similar to interface declarations. Special kinds of annotations include Marker annotations and Single-element annotations. The main reason for annotations is for tools providers.

Neal thought that JDK 5 Beta 3 or Release Candidate was available at http://java.sun.com/j2se/1.5.0, but it looks like Beta 2 is the latest release. The fact that he said that implies that a new release should be available shortly. Neal also mentioned that JDK 5 (final) would be shipping soon.

Random fact: Google uses a lot of Java - entire Ads front-end is done in Java.

This was a great talk about all the new features of JDK 5 - I can't wait to start using them. It might be awhile before I can convert AppFuse to JSP 2.0 and JDK 5, but it'll be a good day when I can write my apps using these technologies. Tonight was the best overview of JDK 5 that I've seen so far - in print or person.

Update: Presentations PDFs have been published: Programming Puzzles and Taming the Tiger.

Posted in Java at Aug 12 2004, 01:01:48 AM MDT 5 Comments

PostgreSQL 8 with AppFuse

I agree with Dion that PostgreSQL is a good database. Thanks to his post, I found the new Windows installer for 8.0. Using it, I was able to quickly setup a database for AppFuse, change my database settings in build.properties and run "ant test-all" successfully. Total time? 5 minutes. That's the way a database installation should be.

I've setup PostgreSQL on OS X before using this package, but now when I try to run it, I get an error "could not read shared memory segment". Time to start digging into config files.

5 minutes later: Using these update instructions, I got everything working again on OS X. To ensure good PostgreSQL support, I'm going to run AppFuse against PostgreSQL (on OS X) from now on.

Posted in Java at Aug 11 2004, 11:56:23 AM MDT Add a Comment

Frustrating day with Linux

I can tell I've been getting a little burned out the last few days. I think it had a lot to do with our builder's death last week. I came to realize that working my ass off just doesn't have that many rewards. For most of the weekends this summer, I've been getting up at 4 and working for a few hours until Julie and Abbie get up. Then I do it again on Monday morning. This weekend I didn't get up before 9. And today I slept until 8 - even though I had planned to get up at 4. To make matters worse, rather than putting in hours for my client today, I spent the entire day wrestling with Linux.

I really wanted to get my new Cinema Display working with Suse and Fedora. I'm almost to the conclusion that it "ain't gonna happen". This sucks b/c now I have to leave one of my huge-n-heavy CRT monitors on my desk. Days like today, where I banged my head against the wall all day, are quite discouraging. My office is in turmoil - with open boxes all over the floor, monitors strewn about and video cards piling up on my desk. Some days are better than others. Hopefully my frustrations from today will turn into some type of writing zone later this week.

Update: I finally gave up and hooked my two Linux boxes up to my old KVM switch and a crappy ol' keyboard/mouse that I had lying around. Then I was planning on hooking my PowerBook and XP box up to my new DVI KVM switch. Wouldn't you know it - it doesn't fricken work. The connector on the cinema display is too fat to even plug into the KVM switch. My guess is that no one is using these displays with a KVM or maybe there's a special switch I have to get. Oh well, I guess I can manually switch the monitor b/w OS X and XP if I really need to.

Posted in General at Aug 09 2004, 10:38:28 PM MDT 11 Comments

My JSF Experience

Of all the MVC Frameworks I've developed with in the last few weeks (Struts, Spring MVC, WebWork and Tapestry) - JSF was by far the worst. And it's not the implementations that are the problem, it's the spec itself (as far as I can tell). Plain and simple, it does not simplify web development.

I spent 3 days developing a simple JSF app - most of it which I had done in the first day. The last 2 days have been spent migrating to MyFaces and trying to find clean ways to do things. My perspective on JSF after this experience? Run away. Run far, far away. All of the above mentioned frameworks are MUCH superior to this technology. Let's get on with the things I learned.

  • MyFaces handles duplicate posts nicely. If you hit "reload" on your browser after saving a record, you get presented with an empty form rather than a duplicate record. I believe I got a duplicate record with Sun's RI.
  • The ability to specify an "action" attribute on a button (or a link) and them map that action to a page (in faces-config.xml) is pretty cool.
  • Every button or link clicked results in a form post. That's just wrong - why can't I have true links like the web is supposed to? So much for bookmarks.
  • Saving state on the client results in enormously long URLs and/or hidden fields.
  • JSF support is fairly non-existent. Unlike the other MVC frameworks, the MyFaces mailing list has hardly any traffic and the Sun forums aren't much better.
  • The MyFaces website seems to be down whenever I want to look something up on it, like right now.
  • I did find some CRUD examples, like this this one, but was disappointed to find that i18n is not considered for setting success messages. I ended up using the solution described in this post. 6 lines of code to set a success message - you've got to be kidding me! Most frameworks have a simple 1-2 liner.
  • Waiting for JSPs to compile the first time has surprisingly become painful after using Tapestry, Velocity and FreeMarker for the last 2 weeks.
  • Integration with Spring is fairly easy (code is in CVS), but MyFaces spits out an error when it shouldn't be.
  • Validation messages are ugly. For instance, when a required field isn't filled in, I get: "lastName": Value is required. I was able to override the default messages, but I was never able to use the label of the field (vs. the field's id).
  • The <h:messages> tag is practically worthless. Sure it's great for displaying messages (error and success), but that's about it. It has a "layout" attribute that doesn't even work in Sun's RI, and in MyFaces it just wraps a <span> with a <ul><li> or a <table>. Both of these layouts are useless b/c you can't set a css class on them. I ended up using "table" and having to set a generic CSS rule (width: 100%) in order to get the message/error bar to show across the top of my page. This tag also doesn't allow you to escape HTML.
  • The <h:dataTable> component is nothing like the displaytag. MyFaces claims to have a pageable/sortable component, but it requires custom logic/methods in your managed-bean. Yuck. I ended up using <h:dataTable>, which has neither sorting or paging. This is only because I couldn't get an <h:commandLink> working inside a displaytag column.
  • JSF-created apps are pretty much untestable. Managed-beans are testable, but the UI seems really difficult with jWebUnit and Canoo's WebTest. IMO, it should be possible to specify a URL to edit a record (i.e. editUser.html?id=2). With JSF and my master/detail app, the link to edit actually sets about 5 hidden form fields with JavaScript and then submits the form. I could probably figure the URL out, but it'd be ugly. Also, the MyFaces <h:dataTable> will not render an "id" attribute if you specify one. This is needed to verify tables and their data with jWebUnit.
  • When using "ant reload" to reload my application (using Tomcat's Ant Tasks), I kept encountering a ThreadDeath error. This seems to be specific to MyFaces as I never saw it with other frameworks or Sun's RI.

Like Tapestry, I felt like I was banging my head against the wall a fair amount. However, with Tapestry (and all the other frameworks), I was able to get exactly the behavior I wanted w/o too much work. I could produce clean and user-friendly error messages - (Tapestry already had clean required messages built in). I was able to write a jUnitWebTest to test all CRUD activities. With JSF, I was able to test one thing - adding a new record. I couldn't edit it b/c the JavaScript support (which I tend to not use) puked every time it encountered a JSF-generated JavaScript function.

My opinion after all of this? If you know Struts, Spring MVC and WebWork are fairly easy to learn. WebWork is simpler and elegant, but Spring MVC supports more view options out-of-the-box. Tapestry is cool, but you'll have to invest a lot of time into learning it and you'll probably get caught up in its cult and forever be claiming "Tapestry Rocks!" which can get annoying to your fellow developers. ;-) Finally, I can confirm that SiteMesh rocks - it worked for all the frameworks I used and I never had to change a single line of code.

Whatever you do, don't use JSF. Not yet anyway.

Posted in Java at Aug 06 2004, 04:53:22 PM MDT 76 Comments

RE: Why use Maven

Warner has a post about why he likes Maven. He might not know it, but he's actually ripping on AppFuse, its directory structure, and build file. I like getting ripped on, so that doesn't bother me. What bother's me is that Warner has comments turned off so no one can get him back. ;-)

The main reason that AppFuse uses Ant over Maven is speed. Maven runs much slower than Ant. Period. Also, with an open source project like AppFuse - I try to appeal to the larger audience, who likely has Ant installed. Other OS projects I work on (displaytag and struts-menu) both use Maven and people have a lot harder time trying to build from source b/c of Maven issues. Lastly, I like having a complete download - rather than download-dependencies-after-you-download-the-project like Maven does. I realize if I did use Maven I could package the dependencies in the app - which is likely what I'd do anyway since the main repositories seem to be constantly out-of-date.

Recently, I had a similar experience to Warner. As part of my current contract, I was tasked to write a couple of Maven sample apps. Warner came to my rescue and helped me out a lot, but I felt like I was jumping through a lot of hoops to do simple stuff that was already done in the Ant version of my app. I guess I'm just not a Maven guy. A project that's done right, regardless of if it's done with Ant or Maven, should build by typing "ant" or "maven" - or at least provide you help on what you need to type. Some projects, like Spring and Struts, actually allow you to use either one out-of-the-box. That's a pretty cool idea and likely keeps everyone happy.

It sounds like Warner has re-worked AppFuse to work with Maven. Care to donate your couple hours of work? I wouldn't use it personally, but there has been interest in a Maven version. Some folks seem to like slow build tools.

Posted in Java at Aug 04 2004, 03:29:04 PM MDT 26 Comments

August is gonna be a rough one

I've got a lot on my plate for August. Probably too much, but I'm going to make a run at it anyway. In addition to my 40-hour per-week contract, I'm going to try and finish off 1.0 of Spring Live and release the next version of AppFuse. Julie and I were talking last week and I estimated that I'd need about 100 hours outside of "work" to accomplish both of these tasks. That's 65 hour weeks, or 12.5 hour days. Yech...

I'm off to a bad start today since I was twidding with my monitor most of the day and only billed 4 hours to my client. Tonight I got a couple hours in on AppFuse, but only minor bug fixes - no major features. It's gonna be rough - if I seem short or don't post much you'll know why. If I did it right, I'd get up at 4 every day and be I'd have my time in + exercise by 6 p.m. every night.

We'll see how it goes - the baby is due September 3rd (a.k.a. Labor Day Weekend) and I'd like to be done with Spring Live 1.0 and AppFuse 1.6 before the little guy/girl comes out. I told Julie if she had it two weeks late it would work out awful nice for me! ;-)

Posted in General at Aug 02 2004, 10:45:24 PM MDT 6 Comments

AppFuse Changes: Unit Testing with Easy Mock and Spring's Struts Plugin

I have a couple of proposal for the next AppFuse release. Let me know what you think:

  • Change service and action/controller tests to use Easy Mock to mock dependencies. This will likely require a bit more code in the test, but it'll allow true unit testing of components. Current tests are more like integrations tests, which tend to be slower. The Canoo WebTests will continue to act as the integration tests that verify functionality top-to-bottom.
  • Change Struts to use Spring's Struts Plugin. XDoclet's Spring stuff should make this pretty easy so you don't have to modify any XML - just like the current situation. The advantage of this is you can use dependency injection on your actions, rather than getBean(...).

I hope to get these in, along with a WebWork option, in the 1.6 release. I'd love to get 1.6 done and released in August, but I'm probably dreaming since I'd like to finish Spring Live in the same time frame. Of course, I'm also planning on fixing any bugs that are currently entered.

Posted in Java at Aug 02 2004, 11:34:21 AM MDT 12 Comments