Tuesday, August 10, 2010

Is Java getting more and more complex

Recently I read an article in Artima, titled "Have Generics Killed Java?". This article is not the first one to complain about the complexities introduced into Java due to Generics. I used to a C++ programmer for around 6 years and been a big fan of the language. When I switched to using Java, during the pre-Generics era, I simply loved the simplicity and lucidness of Java. After reading the section on Generics in Effective Java, and having learnt the IFs and BUTs of the Generics, I realized how many things one has to remember to make effective use of Generics.

I rememberd an answer given by Bjarne Stroustrup, the creator of C++, a few years before the introduction of Generics. The gist if his answer was that every language commercially successful and used in large scale follows exactly the same path C++ and (now) Java is following. That is to start simple and eventually getting more and more complex.

After reading the FAQ for C++0X and some of the modules in Boost library, I now feel that C++ is conquering complexity, especially concurrent programming, using some elegant abstractions. Despite the attempt to conquer complexity, I personally feel that C++0X has too many things to remember :-(

Saturday, August 07, 2010

FEST libraries - a useful set of tools for testing

I came across an article in DZone.com that talked about the FEST libraries. I felt I should have known about the FEST libraries a earlier. They are pretty powerful in terms of expressing test cases in a human readable form. In FEST site itself I found a link to internal DSLs in Java which was quite an interesting reading.

Friday, August 06, 2010

Eclipse Helios JEE and Tomcat issue

I installed the latest Eclipse Helios JEE package. Every time when I try to start my Tomcat instance, I started getting 100% CPU and an non-responsive Eclipse. I figured out that this was an issue with the WTP that comes by default with the Eclipse package (which I think is 3.2.0) and this issue was fixed with WTP version 3.2.1. If you try to update this package by using "Help->Check For Updates" it won't update. So here is how you can update:
  1. Go to "Help->Install New Software".
  2. In the "Work with:" input box, give the URL "http://download.eclipse.org/webtools/repository/helios/".
  3. Wait for all the package information to be downloaded and select "Web Tools Platform (WTP) 3.2.1" option. If you are planning to use any other package, you can select them. But make sure you select the ones from 3.2.1 version distribution.
  4. Click on Next and follow the prompt to complete installation. 
If you restart Eclipse, you should be fine. You should no longer see any 100% CPU issues.

If you are interested in knowing more about the issue, please refer here.

Monday, August 02, 2010

Cobertura and Spring auto proxying

If you are using Cobertrua to get coverage reports, you may run into the error message shown below (lines folded for clarity):
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'myBean' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed;
nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type
'$Proxy28 implementing net.sourceforge.cobertura.coveragedata.HasBeenInstrumented, org.springframework.aop.SpringProxy, org.springframework.aop.framework.Advised' to required type 'com.mydomain.MyDao' for property 'myDao';
nested exception is java.lang.IllegalStateException: Cannot convert value of type
[$Proxy28 implementing net.sourceforge.cobertura.coveragedata.HasBeenInstrumented, org.springframework.aop.SpringProxy, org.springframework.aop.framework.Advised] to required type [com.mydomain.MyDao]
for property 'myDao': no matching editors or conversion strategy found
 Specifically if you are using AspectJ auto proxying, like below:
    <context:annotation-config/>
    <aop:aspectj-autoproxy/>
 To fix the issue, just add the following property:

    <context:annotation-config/>
    <aop:aspectj-autoproxy proxy-target-class="true" />
That should fix the exception shown above. To know more about this property please refer to Spring documentation.

Bean properties printer - a useful debugging tool

There are many instances when I wanted to just log the properties of a given object (most of the time its a bean). This will be useful in two ways: 1) learn about the concrete type of the object 2) serves as a good learning aid to understand what are all the properties that can be get/set in that object. Of course, if you have the documentation and the source code for the class in question, that would be the ultimate aid.

Nevertheless, the following piece of code would be useful to print the properties of the given object/bean, using the getter methods that are available in the object.
    public static void printProperties(String msg, Object o) {
        String className = o.getClass().getName();
        if(msg != null && msg.length() > 0)
            logger.info("{} (type {})", msg, className);
        Method[] methods = o.getClass().getMethods();
        for(Method m:methods) {
            if(m.getName().startsWith("get") && m.getParameterTypes().length == 0) {
                m.setAccessible(true);
                try {
                    Object returnValue = m.invoke(o);
                    logger.info("  {} -> {} (type {})", toObjArr(m.getName(), returnValue,
                            m.getReturnType().getName()));
                } catch (Exception e) {
                    logger.error("Exception thrown while invoking [{}]: {}", m.getName(), e);
                }
            }
        }
    }
You can view the source code of toObjArr() here. This method can be improved a bit. For e.g. methods starting with isXXX are not invoked in the code. Also, a recursive way of printing the properties (with an optional max depth) can be provided.

A sample output could look like this:
Contents of the SAML request (type org.opensaml.saml2.core.impl.AuthnRequestImpl)
   getSubject -> null (type org.opensaml.saml2.core.Subject)
   getOrderedChildren -> [org.opensaml.saml2.core.impl.IssuerImpl@15e14d9, org.opensaml.saml2.core.impl.ScopingImpl@1aacada] (type java.util.List)
   getConditions -> null (type org.opensaml.saml2.core.Conditions)
   getRequestedAuthnContext -> null (type org.opensaml.saml2.core.RequestedAuthnContext)
   getProtocolBinding -> urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST (type java.lang.String)
   getAssertionConsumerServiceIndex -> null (type java.lang.Integer)
   getAssertionConsumerServiceURL -> http://localhost:8080/mySP/resources/saml/SSO (type java.lang.String)
   getAttributeConsumingServiceIndex -> null (type java.lang.Integer)
   getProviderName -> null (type java.lang.String)
   getNameIDPolicy -> null (type org.opensaml.saml2.core.NameIDPolicy)
   getScoping -> org.opensaml.saml2.core.impl.ScopingImpl@1aacada (type org.opensaml.saml2.core.Scoping)
   getVersion -> 2.0 (type org.opensaml.common.SAMLVersion)
   getID -> a3hj688f209c170h433b6eh0h73e0j2 (type java.lang.String)
   getDestination -> http://localhost:8080/myapp/profile/SAML2/POST/SSO (type java.lang.String)
   getIssuer -> org.opensaml.saml2.core.impl.IssuerImpl@15e14d9 (type org.opensaml.saml2.core.Issuer)
   getIssueInstant -> 2010-08-02T18:37:33.528Z (type org.joda.time.DateTime)
   getSignatureReferenceID -> a3hj688f209c170h433b6eh0h73e0j2 (type java.lang.String)
   getConsent -> null (type java.lang.String)
   getExtensions -> null (type org.opensaml.saml2.common.Extensions)
   getValidators -> null (type java.util.List)
   getSignature -> null (type org.opensaml.xml.signature.Signature)
   getParent -> null (type org.opensaml.xml.XMLObject)
   getDOM -> null (type org.w3c.dom.Element)
   getSchemaType -> null (type javax.xml.namespace.QName)
   getElementQName -> {urn:oasis:names:tc:SAML:2.0:protocol}AuthnRequest (type javax.xml.namespace.QName)
   getIDIndex -> org.opensaml.xml.util.IDIndex@1ab000c (type org.opensaml.xml.util.IDIndex)
   getNamespaces -> [xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"] (type java.util.Set)
   getNoNamespaceSchemaLocation -> null (type java.lang.String)
   getSchemaLocation -> null (type java.lang.String)
   getClass -> class org.opensaml.saml2.core.impl.AuthnRequestImpl (type java.lang.Class)

Hope this serves as a useful tool in your troubleshooting/debugging.