Thursday Mar 22, 2012

Why is Java EE 6 better than Spring ?

Java EE 6 was released over 2 years ago and now there are 14 compliant application servers. In all my talks around the world, a question that is frequently asked is

Why should I use Java EE 6 instead of Spring ?

There are already several blogs covering that topic:
I will try to share my perspective in this blog.

First of all, I'd like to start with a note:

Thank you Spring framework for filling the interim gap and providing functionality that is now included in the mainstream Java EE 6 application servers. The Java EE platform has evolved over the years learning from frameworks like Spring and provides all the functionality to build an enterprise application. Thank you very much Spring framework!

While Spring was revolutionary in its time and is still very popular and quite main stream in the same way Struts was circa 2003, it really is last generation's framework - some people are even calling it legacy. However my theory is "code is king". So my approach is to build/take a simple Hello World CRUD application in Java EE 6 and Spring and compare the deployable artifacts.

I started looking at the official tutorial Developing a Spring Framework MVC Application Step-by-Step but it is using the older version 2.5. I wasn't able to find any updated version in the current 3.1 release. Next, I downloaded Spring Tool Suite and thought that would provide some template samples to get started. A least a quick search did not show any handy tutorials - either video or text-based. So I searched and found a link to their SVN repository at

I tried the "mvc-basic" sample and the generated WAR file was 4.43 MB. While it was named a "basic" sample it seemed to come with 19 different libraries bundled but it was what I could find:

And it is not even using any database!

The app deployed fine on GlassFish 3.1.2 but the "@Controller Example" link did not work as it was missing the context root. With a bit of tweaking I could deploy the application and assume that the account got created because no error was displayed in the browser or server log.

Next I generated the WAR for "mvc-ajax" and the 5.1 MB WAR had 20 JARs (1 removed, 2 added):

2 more JARs for just doing Ajax.

Anyway, deploying this application gave the following error:

Caused by: java.lang.NoSuchMethodError:<init>(Lorg/codehaus/jackson/map/ClassIntrospector;Lorg/codehaus/jackson/map/AnnotationIntrospector;Lorg/codehaus/jackson/map/introspect/VisibilityChecker;Lorg/codehaus/jackson/map/jsontype/SubtypeResolver;)V
    at org.springframework.samples.mvc.ajax.json.ConversionServiceAwareObjectMapper.<init>(
    at org.springframework.samples.mvc.ajax.json.JacksonConversionServiceConfigurer.postProcessAfterInitialization(

Seems like some incorrect repos in the "pom.xml".

Next one is "mvc-showcase" and the 6.49 MB WAR now has 28 JARs as shown below:


The app at least deployed and showed results this time. But still no database!

Next I tried building "jpetstore" and got the error:

[ERROR] Failed to execute goal on project org.springframework.samples.jpetstore:
Could not resolve dependencies for project org.springframework.samples:
org.springframework.samples.jpetstore:war:1.0.0-SNAPSHOT: Failed to collect
dependencies for [commons-fileupload:commons-fileupload:jar:1.2.1 (compile), (compile),
javax.xml.rpc:com.springsource.javax.xml.rpc:jar:1.1.0 (compile), (compile),
commons-io:commons-io:jar:1.3.2 (compile), hsqldb:hsqldb:jar: (compile),
org.apache.tiles:tiles-core:jar:2.2.0 (compile), org.apache.tiles:tiles-jsp:jar:2.2.0 (compile),
org.tuckey:urlrewritefilter:jar:3.1.0 (compile), org.springframework:spring-webmvc:jar:
3.0.0.BUILD-SNAPSHOT (compile), org.springframework:spring-orm:jar:3.0.0.BUILD-SNAPSHOT (compile),
org.springframework:spring-context-support:jar:3.0.0.BUILD-SNAPSHOT (compile),
org.springframework.webflow:spring-js:jar:2.0.7.RELEASE (compile), org.apache.ibatis: (runtime),
caucho:jar:3.2.1 (compile), (compile),
javax.wsdl:com.springsource.javax.wsdl:jar:1.6.1 (compile), javax.servlet:jstl:jar:1.2 (runtime),
org.aspectj:aspectjweaver:jar:1.6.5 (compile), javax.servlet:servlet-api:jar:2.5 (provided),
javax.servlet.jsp:jsp-api:jar:2.1 (provided), junit:junit:jar:4.6 (test)]: Failed to read
artifact descriptor for org.springframework:spring-webmvc:jar:3.0.0.BUILD-SNAPSHOT: Could
not transfer artifact org.springframework:spring-webmvc:pom:3.0.0.BUILD-SNAPSHOT from/to
JBoss repository ( Access denied to: http://
It appears the sample is broken - maybe I was pulling from the wrong repository - would be great if someone were to point me at a good target to use here.

With a 50% hit on samples in this repository, I started searching through numerous blogs, most of which have either outdated information (using XML-heavy Spring 2.5), some piece of configuration (which is a typical "feature" of Spring) is missing, or too much complexity in the sample. I finally found this blog that worked like a charm. This blog creates a trivial Spring MVC 3 application using Hibernate and MySQL. This application performs CRUD operations on a single table in a database using typical Spring technologies.  I downloaded the sample code from the blog, deployed it on GlassFish 3.1.2 and could CRUD the "person" entity. The source code for this application can be downloaded here. More details on the application statistics below.

And then I built a similar CRUD application in Java EE 6 using NetBeans wizards in a couple of minutes. The source code for the application can be downloaded here and the WAR here.

The Spring Source Tool Suite may also offer similar wizard-driven capabilities but this blog focus primarily on comparing the runtimes. The lack of STS tutorials was slightly disappointing as well. NetBeans however has tons of text-based and video tutorials and tons of material even by the community. One more bit on the download size of tools bundle ...

NetBeans 7.1.1 "All" is 211 MB (which includes GlassFish and Tomcat)
Spring Tool Suite  2.9.0 is 347 MB (~ 65% bigger)

This blog is not about the tooling comparison so back to the Java EE 6 version of the application ....

In order to run the Java EE version on GlassFish, copy the MySQL Connector/J to glassfish3/glassfish/domains/domain1/lib/ext directory and create a JDBC connection pool and JDBC resource as:
./bin/asadmin create-jdbc-connection-pool --datasourceclassname \\
com.mysql.jdbc.jdbc2.optional.MysqlDataSource --restype \\
javax.sql.DataSource --property \\
portNumber=3306:user=mysql:password=mysql:databaseName=mydatabase \\
./bin/asadmin create-jdbc-resource --connectionpoolid myConnectionPool jdbc/myDataSource

I generated WARs for the two projects and the table below highlights some differences between them:

Java EE 6
WAR File Size
0.021030 MB
10.87 MB (~516x)
Number of files
53 (> 2.5x)
Bundled libraries
Total size of libraries
12.1 MB
XML files
LoC in XML files
50 (11 + 15 + 24) 129 (27 + 46 + 16 + 11 + 19) (~ 2.5x)
Total .properties files
Cold Deploy
5,339 ms
11,724 ms
Second Deploy
481 ms
6,261 ms
Third Deploy
528 ms
5,484 ms
Fourth Deploy
484 ms
5,576 ms
Runtime memory
~73 MB
~101 MB

Some points worth highlighting from the table ...
  • 516x WAR file, 10x deployment time - With 12.1 MB of libraries (for a very basic application) bundled in your application, the WAR file size and the deployment time will naturally go higher. The WAR file for Spring-based application is 516x bigger and the deployment time is double during the first deployment and ~ 10x during subsequent deployments. The Java EE 6 application is fully portable and will run on any Java EE 6 compliant application server.
  • 36 libraries in the WAR - There are 14 Java EE 6 compliant application servers today. Each of those servers provide all the functionality like transactions, dependency injection, security, persistence, etc typically required of an enterprise or web application. There is no need to bundle 36 libraries worth 12.1 MB for a trivial CRUD application. These 14 compliant application servers provide all the functionality baked in.

    Now you can also deploy these libraries in the container but then you don't get the "portability" offered by Spring in that case. Does your typical Spring deployment actually do that ?
  • 3x LoC in XML - The number of XML files is about 1.6x and the LoC is ~ 2.5x. So much XML seems circa 2003 when the Java language had no annotations. The XML files can be further reduced, e.g. faces-config.xml can be replaced without providing i18n, but I just want to compare stock applications.
  • Memory usage - Both the applications were deployed on default GlassFish 3.1.2 installation and any additional memory consumed as part of deployment/access was attributed to the application. This is by no means scientific but at least provides an initial ballpark. This area definitely needs more investigation.

Another table that compares typical Java EE 6 compliant application servers and the custom-stack created for a Spring application ...

Java EE 6
Web Container

53 MB (tcServer 2.6.3 Developer Edition)
12 MB (Spring Security 3.1.0)
6.3 MB (Hibernate 4.1.0, required)
Dependency Injection
5.3 MB (Framework)
Web Services
796 KB (Spring WS 2.0.4)
3.4 MB (RabbitMQ Server 2.7.1)
936 KB (Java client 936)
1.3 MB (Spring OSGi 1.2.1)

GlassFish and WebLogic (starting at 33 MB)
83.3 MB

There are differentiating factors on both the stacks. But most of the functionality like security, persistence, and dependency injection is baked in a Java EE 6 compliant application server but needs to be individually managed and patched for a Spring application. This very quickly leads to a "stack explosion". The Java EE 6 servers are tested extensively on a variety of platforms in different combinations whereas a Spring application developer is responsible for testing with different JDKs, Operating Systems, Versions, Patches, etc. Oracle has both the leading OSS lightweight server with GlassFish and the leading enterprise Java server with WebLogic Server, both Java EE 6 and both with lightweight deployment options.

The Web Container offered as part of a Java EE 6 application server not only deploys your enterprise Java applications but also provide operational management, diagnostics, and mission-critical capabilities required by your applications.

The Java EE 6 platform also introduced the Web Profile which is a subset of the specifications from the entire platform. It is targeted at developers of modern web applications offering a reasonably complete stack, composed of standard APIs, and is capable out-of-the-box of addressing the needs of a large class of Web applications. As your applications grow, the stack can grow to the full Java EE 6 platform. The GlassFish Server Web Profile starting at 33MB (smaller than just the non-standard tcServer) provides most of the functionality typically required by a web application. WebLogic provides battle-tested functionality for a high throughput, low latency, and enterprise grade web application. No individual managing or patching, all tested and commercially supported for you!

Note that VMWare does have a server, tcServer, but it is non-standard and not even certified to the level of the standard Web Profile most customers expect these days. Customers who choose this risk proprietary lock-in since VMWare does not seem to want to formally certify with either Java EE 6 Enterprise Platform or with Java EE 6 Web Profile but of course it would be great if they were to join the community and help their customers reduce the risk of deploying on VMWare software.

Some more points to help you decide choose between Java EE 6 and Spring ...

  • Freedom to choose container - There are 14 Java EE 6 compliant application servers today, with a variety of open source and commercial offerings. A Java EE 6 application can be deployed on any of those containers. So if you deployed your application on GlassFish today and would like to scale up with your demands then you can deploy the same application to WebLogic. And because of the portability of a Java EE 6 application, you can even take it a different vendor altogether.

    Spring requires a runtime which could be any of these app servers as well. But why use Spring when all the required functionality is already baked into the application server itself ?

    Spring also has a different definition of portability where they claim to bundle all the libraries in the WAR file and move to any application server. But we saw earlier how bloated that archive could be.

    The equivalent features in Spring runtime offerings (mainly tcServer) are not all open source, not as mature, and often require manual assembly. 
  • Vendor choice - The Java EE 6 platform is created using the Java Community Process where all the big players like Oracle, IBM, RedHat, and Apache are conritbuting to make the platform successful. Each application server provides the basic Java EE 6 platform compliance and has its own competitive offerings. This allows you to choose an application server for deploying your Java EE 6 applications. If you are not happy with the support or feature of one vendor then you can move your application to a different vendor because of the portability promise offered by the platform.

    Spring is a set of products from a single company, one price book, one support organization, one sustaining organization, one sales organization, etc. If any of those cause a customer headache, where do you go ? Java EE, backed by multiple vendors, is a safer bet for those that are risk averse.
  • Production support - With Spring, typically you need to get support from two vendors - VMWare and the container provider. With Java EE 6, all of this is typically provided by one vendor. For example, Oracle offers commercial support from systems, operating systems, JDK, application server, and applications on top of them. VMWare certainly offers complete production support but do you really want to put all your eggs in one basket ?

    Do you really use tcServer ? ;-)
  • Maintainability - With Spring, you are likely building your own distribution with multiple JAR files, integrating, patching, versioning, etc of all those components. Spring's claim is that multiple JAR files allow you to go à la carte and pick the latest versions of different components. But who is responsible for testing whether all these versions work together ?

    Yep, you got it, its YOU!
    If something does not work, who patches and maintains the JARs ? Of course, you!
    Commercial support for such a configuration ? On your own!

    The Java EE application servers manage all of this for you and provide a well-tested and commercially supported bundle.
While it is always good to realize that there is something new and improved that updates and replaces older frameworks like Spring, the good news is not only does a Java EE 6 container offer what is described here, most also will let you deploy and run your Spring applications on them while you go through an upgrade to a more modern architecture. End result, you get the best of both worlds - keeping your legacy investment but moving to a more agile, lightweight world of Java EE 6.

A message to the Spring lovers ...

The complexity in J2EE 1.2, 1.3, and 1.4 led to the genesis of Spring but that was in 2004. This is 2012 and the name has changed to "Java EE 6" :-) There are tons of improvements in the Java EE platform to make it easy-to-use and powerful. Some examples:
  • Adding @Stateless on a POJO makes it an EJB
  • EJBs can be packaged in a WAR with no special packaging or deployment descriptors
  • "web.xml" and "faces-config.xml" are optional in most of the common cases
  • Typesafe dependency injection is now part of the Java EE platform
  • Add @Path on a POJO allows you to publish it as a RESTful resource
  • EJBs can be used as backing beans for Facelets-driven JSF pages providing full MVC
  • Java EE 6 WARs are known to be kilobytes in size and deployed in milliseconds
  • Tons of other simplifications in the platform and application servers
So if you moved away from J2EE to Spring many years ago and have not looked at Java EE 6 (which has been out since Dec 2009) then you should definitely try it out. Just be at least aware of what other alternatives are available instead of restricting yourself to one stack. Here are some workshops and screencasts worth trying:
  • screencast #37 shows how to build an end-to-end application using NetBeans
  • screencast #36 builds the same application using Eclipse
  • javaee-lab-feb2012.pdf is a 3-4 hours self-paced hands-on workshop that guides you to build a comprehensive Java EE 6 application using NetBeans
Each city generally has a "spring cleanup" program every year. It allows you to clean up the mess from your house. For your software projects, you don't need to wait for an annual event, just get started and reduce the technical debt now! Move away from your legacy Spring-based applications to a lighter and more modern approach of building enterprise Java applications using Java EE 6.

Watch this beautiful presentation that explains how to migrate from Spring -> Java EE 6:

List of files in the Java EE 6 project:


List of files in the Spring 3.x project:

./WEB-INF/classes/org./WEB-INF/classes/org/krams ./WEB-INF/classes/org/krams/tutorial ./WEB-INF/classes/org/krams/tutorial/controller ./WEB-INF/classes/org/krams/tutorial/controller/MainController.class ./WEB-INF/classes/org/krams/tutorial/domain ./WEB-INF/classes/org/krams/tutorial/domain/Person.class ./WEB-INF/classes/org/krams/tutorial/service ./WEB-INF/classes/org/krams/tutorial/service/PersonService.class ./WEB-INF/hibernate-context.xml ./WEB-INF/hibernate.cfg.xml ./WEB-INF/jsp ./WEB-INF/jsp/addedpage.jsp ./WEB-INF/jsp/addpage.jsp ./WEB-INF/jsp/deletedpage.jsp ./WEB-INF/jsp/editedpage.jsp ./WEB-INF/jsp/editpage.jsp ./WEB-INF/jsp/personspage.jsp ./WEB-INF/lib ./WEB-INF/lib/antlr-2.7.6.jar ./WEB-INF/lib/aopalliance-1.0.jar ./WEB-INF/lib/c3p0- ./WEB-INF/lib/cglib-nodep-2.2.jar ./WEB-INF/lib/commons-beanutils-1.8.3.jar ./WEB-INF/lib/commons-collections-3.2.1.jar ./WEB-INF/lib/commons-digester-2.1.jar ./WEB-INF/lib/commons-logging-1.1.1.jar ./WEB-INF/lib/dom4j-1.6.1.jar ./WEB-INF/lib/ejb3-persistence-1.0.2.GA.jar ./WEB-INF/lib/hibernate-annotations-3.4.0.GA.jar ./WEB-INF/lib/hibernate-commons-annotations-3.1.0.GA.jar ./WEB-INF/lib/hibernate-core-3.3.2.GA.jar ./WEB-INF/lib/ ./WEB-INF/lib/jstl-1.1.2.jar ./WEB-INF/lib/jta-1.1.jar ./WEB-INF/lib/junit-4.8.1.jar ./WEB-INF/lib/log4j-1.2.14.jar ./WEB-INF/lib/mysql-connector-java-5.1.14.jar ./WEB-INF/lib/persistence-api-1.0.jar ./WEB-INF/lib/slf4j-api-1.6.1.jar ./WEB-INF/lib/slf4j-log4j12-1.6.1.jar ./WEB-INF/lib/spring-aop-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-asm-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-beans-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-context-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-context-support-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-core-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-expression-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-jdbc-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-orm-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-tx-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-web-3.0.5.RELEASE.jar ./WEB-INF/lib/spring-webmvc-3.0.5.RELEASE.jar ./WEB-INF/lib/standard-1.1.2.jar ./WEB-INF/lib/xml-apis-1.0.b2.jar ./WEB-INF/spring-servlet.xml ./WEB-INF/ ./WEB-INF/web.xml

So, are you excited about Java EE 6 ? Want to get started now ? Here are some resources:

Wednesday Nov 02, 2011

Migrating Spring to Java EE 6 Article Series

Java EE 6 with its light-weight, easy-to-use, and simplified yet powerful functionality is very compelling. This is the only standards-based enterprise Java platform supported by multiple vendors including, but not limited to, Oracle, IBM, Apache, Caucho, and others.

To highlight some advantages of the Java EE 6 platform (and brush up some ;-) ...

How do you write an EJB ?

public class MyEJB {
    public doTransaction() {
        . . .

And package it in a WAR, no deployment descriptor or special packaging. Don't keep blowing the J2EE 1.3/1.4 horn guys!

How do you inject a bean or multiple implementations of service in another class ?
@Inject [@SomeQualifier] MyEJB
Yes, Contexts and Dependency Injection provide lot more rich functionality in the platform.

How do you schedule a timed task ? - Just add
on a public method of an EJB>

How do you expose a POJO as a RESTful entity ?

public class MyResource {
    public String myGet() {
        . . .
JSF 2 now uses Facelets-based templating language, allow composite components to be written very easily, truly enforce MVC-based pattern, and lot more benefits.

What does a Servlet look like ?

public class MyServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        . . .

And no "web.xml" here as well.

With a wide variety of development (NetBeans, Eclipse, IntelliJ) and deployment options (GlassFish, JBoss, Caucho, TomEE, ...) and no vendor lock-in, Java EE 6 is the only platform you need to build your enterprise applications. Read more benefits of the platform by the actual users here.

With all these benefits of Java EE 6, here is a very timely multi-part article by David Heffelfinger showing how to migrate your applications from Spring -> Java EE 6. Don't wait, you can deploy Java EE 6 applications on GlassFish (along with commercial support from Oracle) today!

Part 1 is now available.

Let us know what you think!

Thursday Jun 03, 2010

Jazoon 2010 Day 3 - Java EE 6 on Cloud, HTML 5 with JSF 2 and another run on Üetliberg

The Day 3 of Jazoon (Day 1 & 2) started with a great presentation on Gaia satellite and Data Processing by William O'Mullane. Gaia is a European Space Agency space mission that will be launched in Summer of 2012 to compile a catalog of approximately 1 billion stars. Most of their software is Java-based and have been fairly happy with the decision taken 10 years ago. They are very happy with the performance of Java and in certain cases its even 10x faster than C.

I gave a talk on "Running Java EE 6 applications in the Cloud". The talk explained flexibility, light-weight, extensibility, and ease-of-use of Java EE 6. It demonstrated a simple sample development and rapid deployment feature using NetBeans IDE. And then quickly jumped into how this application can be deployed on Amazon EC2, RightScale, Elastra, and Joyent infrastructure. I learned about the Simple Cloud API (Storage only) and Apache libcloud from Doug Tidwell's talk yesterday and so will try them as well.

I gave a tee-shirt from the Bay Area JUG Roundup to Rainer Grau - moderator of the conference and he was kind enough to change it for rest of the day. See his picture below.

The slides from my talk are available below:

More detailed steps to deploy your Java EE 6 application on each cloud management / provider mentioned above will be available in a later blog. Instant feedback via twitter is always much appreciated as shown in the case below:

The Spring 3.0 Themes and Trends talk was quite a dejavu because it was mostly a rehash of what is available in the Java EE 6 today. And I could not understand why would anybody use Spring (instead of Java EE) to use the goodness of the JSF and JPA technologies ?

Roger's talk on "Exploring HTML 5 with JSF 2" was very interesting and had a packed room, small but packed. He showed lots of HTML 5 samples and how Java Server Faces 2 can be used to include new tags like audio / video in a JSF composite component, Web Sockets and even Web Workers with JSF 2. His slides are available at:

Roger & I will work on publishing detailed steps on these demos in the coming days.

Spring Roo was a good one but it seems like that its basically trying to bring Ruby-on-Rails concepts like Dynamic Functions and Scaffold with some usual tooling tricks and heavy code generation to the Java programming language. One more framework, one more convention, one more programming style ... not sure if it fills any gap!

Dan & Aslak presented on Real Java EE Testing with Arquillian and this was mostly a demo-driven talk showing how different Java EE technologies can be easily tested using ShrinkWrap and Arquillian. And the cool thing is that they support deployment to GlassFish Embedded as well.

Here are some pictures from earlier today:

And the day concluded with yet another great run up Üetliberg, just a simple out & back but 1404 ft elevation gain in 4.59 miles. The elevation map is shown below:

More details about the run are given below:

Here are some pictures captured during the run:

It is just beautiful - definitely worth going at least once!

Last but not the least, Roger & I had a great dinner at au gratin - a great restaurant + adjoining bar on the first floor on Bahnhofplatz. They've got great food variety at a great location, reasonably priced (as per the Swiss standards ;-), and an American Football aficionado server by the name David. If you meet him, say our hello to him :-)

And here is the complete photo album:

This was my first Jazoon conference in the beautiful country of Switzerland and I thoroughly enjoyed it. I had some useful conversations and made some good contacts. I'd love to come back here again next year as well!

Next step Über Conf ...

Technorati: conf jazoon zurich javaee glassfish cloud amazon rightscale elastra joyent html5 jsf2 spring

Monday Apr 16, 2007

Spring Flowers

Follow up here.

Spring is now approx 4 weeks old and here are some more pictures from the neighborhood.

I hope we continue to see these and more flowers blossoming in the season, specially since Mercury News has declared drought. My son is a big "water saver" following three steps:

  • 2 minute shower instead of regular 10 minutes (less time and water, both precious at this stage)
  • Not opening the tap fully when washing hands and washing them quickly.
  • Planning to get less number of plants from Home Depot and even those that need less water

He even pasted a note in our living room and asked all his friends to save water. Drop by drop, we will all get through it.

I plan to post more tips on water saving in subsequent entries.

Technorati: nikon d80 digital spring blossoms photography

Saturday Mar 03, 2007

Spring Blossoms

Spring is still 2 weeks away (starting Mar 21) but blossoms are showing up for past few days now. Finally this morning I spent some time this morning in backyard and neighborhood taking some pictures. All of these pictures were taken between 9:00-10:00am, when the sun was bright, using Macro mode of Nikon D80.

The macro mode is good but is not able to focus if the subject is closer than 3-4 inches. I hope to spend some more time over the coming weekends exploring this mode and share some more pictures. 

Here are some flower photography tips:

Please leave a comment if you have any other tips on nature photography.

UPDATE: Follow the discussion on these pictures in Nikonians Forum.

Technorati: nikon d80 digital spring blossoms photography photographytips


profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.

Java EE 7 Samples

Stay Connected


« August 2016