views:

1346

answers:

4

After seeing many hidden features about programming language, i would like to know hidden features of Spring "de facto" framework. As you know, Spring documentation hides many features and would be nice to share it.

And you: what hidden feature of Spring framework do you know ?

A: 

The best way to find any hidden features in Spring would require just looking at the source code.

It is hard to say what is a hidden feature though as Spring is very flexible with the annotations, AspectJ and usage of DI.

James Black
A: 

One is the use of CGLib based class proxies for Spring's AOP. It can also be done via Java's dynamic proxies but default is CGLib. So don't be surprised if you see CGLib in your stack trace.

Other is the use of AOP for DI. Yes, it's all AOP everywhere without you knowing it. It's cool to know that your code is AOP based even if you are only using Spring for DI purposes.

Monis Iqbal
+19  A: 

Spring has a powerful built-in StringUtils class

Notice the following array containing a set of id's

String [] idArray = new String [] {"0", "1", "2", "0", "5", "2"} 

And you want to remove duplicate references. Just do it

idArray = StringUtils.removeDuplicateStrings(idArray);

Now idArray will contain {"0", "1", "2", "5"}.

And much more.


Is it possible to use a Controller class without declare them in web application context file ?

Yes, just put @Component in its declaration (@Controller does not work as expected)

package br.com.spring.view.controller

@Component
public class PlayerController extends MultiActionController {

    private Service service;

    @Autowired
    public PlayerController(InternalPathMethodNameResolver ipmnr, Service service) {
        this.service = service;

        setMethodNameResolver(ipmnr);
    }

    // mapped to /player/add
    public ModelAndView add(...) {}

    // mapped to /player/remove
    public ModelAndView remove(...) {}

    // mapped to /player/list
    public ModelAndView list(...) {}

}

So in web application context file put the following

<beans ...>
    <context:component-scan base-package="br.com.spring.view"/>
    <context:annotation-config/>
    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
        <property name="order" value="0"/>
        <property name="caseSensitive" value="true"/>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver"/>
</beans>

Nothing else


Validation in dynamic forms ?

Use the following

public class Team {

    private List<Player> playerList;    

}

So in Team validator put

@Component
public class TeamValidator implements Validator {

    private PlayerValidator playerValidator;

    @Autowired
    public TeamValidator(PlayerValidator playerValidator) {
        this.playerValidator = playerValidator;
    }

    public boolean supports(Class clazz) {
        return clazz.isAssignableFrom(Team.class);
    }

    public void validate(Object command, Errors errors) {
        Team team = (Team) command;

        // do Team validation

        int index = 0;
        for(Player player: team.getPlayerList()) {
            // Notice code just bellow
            errors.pushNestedPath("playerList[" + index++ + "]");

            ValidationUtils.invokeValidator(playerValidator, player, errors);

            errors.popNestedPath();
        }

    }

}

Inheritance in web forms ?

Use ServlerRequestDataBinder along with hidden form flag

public class Command {

    private Parent parent;

}

public class Child extends Parent { ... }

public class AnotherChild extends Parent { ... }

And in your controller do the following

public class MyController extends MultiActionController {

    public ModelAndView action(HttpServletRequest request, HttpServletResponse response, Object command) {

        Command command = (Command) command;

        // hidden form flag
        String parentChildType = ServletRequestUtils.getRequiredStringParameter(request, "parentChildType");

        // getApplicationContext().getBean(parentChildType) retrieves a Parent object from a application context file
        ServletRequestDataBinder binder = 
            new ServletRequestDataBinder(getApplicationContext().getBean(parentChildType));

        // populates Parent child object
        binder.bind(request);

        command.setParent((Parent) binder.getTarget());
}

Spring has a built-in scanner class ClassPathScanningCandidateComponentProvider. You can use it to find annotations, for instance.

ClassPathScanningCandidateComponentProvider scanner =
    new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());

Spring has a useful org.springframework.util.FileCopyUtils class. You can copy a uploaded file by using

public ModelAndView action(...) throws Exception {

    Command command = (Command) command;

    MultiPartFile uploadedFile = command.getFile();

    FileCopyUtils.copy(uploadedFile.getBytes(), new File("destination"));

If you use a annotation based controller (Spring 2.5+) OR plain MVC Spring controller, you can use a WebBindingInitializer to register global property editors. Something like

public class GlobalBindingInitializer implements WebBindingInitializer {

    public void initBinder(WebDataBinder binder, WebRequest request) {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd/MM/yyyy", true);
    }

}

So in your web application context file, declare

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="GlobalBindingInitializer"/>
    </property>
</bean>

This way any annotation based controller can use any property editor declared in GlobalBindingInitializer.

And so on...

regards,

Arthur Ronald F D Garcia
+7  A: 

Spring can be used as an event bus replacement, since the ApplicationContext is also an ApplicationEventPublisher

The reference Spring implementation is to be found in SimpleApplicationEventMulticaster, which can optionally use a thread pool to distribute the events asynchronously.

Robert Munteanu
Useful stuff, this. The code that does the work is `SimpleApplicationEventMulticaster`, which can optionally use a thread pool to distribute the events asynchronously. I for one am bored of writing code to do this.
skaffman