Hot questions for Annotations in Spring

Top 10 Java Open Source / Spring / Annotations in Spring

Question:

I would like to inject a specific JdbcTemplatein a Spring Boot project. I tried to follow this example for multiple DataSourceconfiguration : http://spring.io/blog/2014/05/27/spring-boot-1-1-0-m2-available-now

My code does compile and run, but only the DataSource with the @Primaryannotation is taken into account, no matter what I put as @Qualifier in the SqlServiceclass. My relevant code is the following :

DatabaseConfig.java:

@Configuration
public class DatabaseConfig {

    @Bean(name = "dsSlave")
    @ConfigurationProperties(prefix="spring.mysql_slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dsMaster")
    @Primary
    @ConfigurationProperties(prefix="spring.mysql_master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "jdbcSlave")
    @Autowired
    @Qualifier("dsSlave")
    public JdbcTemplate slaveJdbcTemplate(DataSource dsSlave) {
        return new JdbcTemplate(dsSlave);
    }

    @Bean(name = "jdbcMaster")
    @Autowired
    @Qualifier("dsMaster")
    public JdbcTemplate masterJdbcTemplate(DataSource dsMaster) {
        return new JdbcTemplate(dsMaster);
    }

}

And I did a quick service to try it out :

SqlService.java:

@Component
public class SqlService {

    @Autowired
    @Qualifier("jdbcSlave")
    private JdbcTemplate jdbcTemplate;

    public String getHelloMessage() {
        String host = jdbcTemplate.queryForObject("select @@hostname;", String.class);
        System.out.println(host);
        return "Hello";
    }

}

Answer:

It should looks like this:

@Bean(name = "jdbcSlave")
@Autowired
public JdbcTemplate slaveJdbcTemplate(@Qualifier("dsSlave") DataSource dsSlave) {
    return new JdbcTemplate(dsSlave);
}

Question:

Is there any way to use Lookup Method Injection using annotations?

Given the following class:

@Service
public abstract class A {


    protected abstract createB();

}

In order to get it to work I have to declare in spring applicationContext.xml the following:

<bean id="b" class="com.xyz.B">
</bean>

<bean id="a" class="com.xyz.A">
    <lookup-method name="createB" bean="b"/>
</bean>

Even though I am using <context:component-scan base> I have to declare it also in the XML. Not a good approach I think.

How to do it with annotations?


Answer:

It is possible to use javax.inject.Provider. All thanks go to Phil Webb.

public class MySingleton {

  @Autowired
  private Provider<MyPrototype> myPrototype;

  public void operation() {
    MyPrototype instance = myPrototype.get();
    // do something with the instance
  }

}

Question:

In Spring Framework , AbstractWizardFormController seems deprecated. How to implement multiple pages form in the Spring MVC Framework. (I am not using webflow)

any example or pointer would help considering my limited knowledge in Spring.


Answer:

A @Controller is a more flexible way to define a form / wizard. You are supposed to map methods to requests based on requested path / request parameters / request method. So instead of defining a list of views and processing the request based on some required "step" parameter, you can define the steps of your wizard as you wish (also the command object will be handled more transparently). Here's how you can get to emulate a classic AWFC functionality (this is only meant to be an example, there's a lot more you can do).

@Controller
@RequestMapping("/wizard.form")
@SessionAttributes("command")
public class WizardController {

    /**
     * The default handler (page=0)
     */
    @RequestMapping
    public String getInitialPage(final ModelMap modelMap) {
        // put your initial command
        modelMap.addAttribute("command", new YourCommandClass());
        // populate the model Map as needed
        return "initialView";
    }

    /**
     * First step handler (if you want to map each step individually to a method). You should probably either use this
     * approach or the one below (mapping all pages to the same method and getting the page number as parameter).
     */
    @RequestMapping(params = "_step=1")
    public String processFirstStep(final @ModelAttribute("command") YourCommandClass command,
                                   final Errors errors) {
        // do something with command, errors, request, response,
        // model map or whatever you include among the method
        // parameters. See the documentation for @RequestMapping
        // to get the full picture.
        return "firstStepView";
    }

    /**
     * Maybe you want to be provided with the _page parameter (in order to map the same method for all), as you have in
     * AbstractWizardFormController.
     */
    @RequestMapping(method = RequestMethod.POST)
    public String processPage(@RequestParam("_page") final int currentPage,
                              final @ModelAttribute("command") YourCommandClass command,
                              final HttpServletResponse response) {
        // do something based on page number
        return pageViews[currentPage];
    }

    /**
     * The successful finish step ('_finish' request param must be present)
     */
    @RequestMapping(params = "_finish")
    public String processFinish(final @ModelAttribute("command") YourCommandClass command,
                                final Errors errors,
                                final ModelMap modelMap,
                                final SessionStatus status) {
        // some stuff
        status.setComplete();
        return "successView";
    }

    @RequestMapping(params = "_cancel")
    public String processCancel(final HttpServletRequest request,
                                final HttpServletResponse response,
                                final SessionStatus status) {
        status.setComplete();
        return "canceledView";
    }

}

I tried to vary the method signatures so that you can get an idea about the flexibility I mentioned. Of course, there's a lot more to it: you can make use of request method (GET or POST) in the @RequestMapping, you can define a method annotated with @InitBinder, etc.

EDIT: I had an unmapped method which I fixed (by the way, you need to make sure you don't have ambiguous mappings -- requests that could be mapped to more than one method -- or unmapped requests -- requests that cannot be mapped to any method). Also have a look at @SessionAttributes, @SessionStatus and @ModelAttribute, which are also needed for fully simulating the behaviour of the classic AWFC (I edited the code already to make this clear).

Question:

My maven spring project directory structure is shown below. I am using Spring-4 annotation based configuration. I configure the resources like below. I tried many ways that are suggested in many Stackoverflow questions and other websites

Spring 4 loading static resources

http://imwill.com/spring-mvc-4-add-static-resources-by-annotation/#.U5GZlXKs9i4

But the jsp files could not load the resources, all the static content requests returns 404 error. I tried these things in jsp,

 <link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">
 <link href="/resources/css/bootstrap.css" rel="stylesheet" media="screen">
 <link href="css/bootstrap.css" rel="stylesheet" media="screen">

EDIT: I am using servlet 2.5 because as of now I cannot upgrade my project from JBoss 5 to higher versions. JBoss5 do not support servlets 3, and do that matter?

@Configuration
@ComponentScan("com.mgage.mvoice")
public class MyAppWebConfig extends WebMvcConfigurerAdapter {
     public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        // I tried these many combinations separately.

        ResourceHandlerRegistration resourceRegistration = registry
            .addResourceHandler("resources/**");
        resourceRegistration.addResourceLocations("/resources/**");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/**");
        registry.addResourceHandler("/img/**").addResourceLocations("/img/**");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/**");
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("classpath:/resources/"); 
              // do the classpath works with the directory under webapp?
     }

}


Answer:

this worked,

   registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");

and in the jsp files I referred to the static resources like

<link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">

Question:

I have an controller that returns JSON. It takes a form, which validates itself via spring annotations. I can get FieldError list from BindingResult, but they don't contain the text that a JSP would display in the tag. How can I get the error text to send back in JSON?

@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
JSONResponse submit(@Valid AnswerForm answerForm, BindingResult result, Model model, HttpServletRequest request, HttpServletResponse response) {

    if (result.hasErrors()) {
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        JSONResponse r = new JSONResponse();
        r.setStatus(JSONResponseStatus.ERROR);
        //HOW DO I GET ERROR MESSAGES OUT OF BindingResult??? 
    } else {
        JSONResponse r = new JSONResponse();
        r.setStatus(JSONResponseStatus.OK);
        return r;
    }

}

JSONREsponse class is just a POJO

public class JSONResponse implements Serializable {
    private JSONResponseStatus status;
    private String error;
    private Map<String,String> errors;
    private Map<String,Object> data;

...getters and setters...
}

Calling BindingResult.getAllErrors() returns an array of FieldError objects, but it doesn't have the actual errors.


Answer:

Disclaimer: I still do not use Spring-MVC 3.0

But i think the same approach used by Spring 2.5 can fullfil your needs

for (Object object : bindingResult.getAllErrors()) {
    if(object instanceof FieldError) {
        FieldError fieldError = (FieldError) object;

        System.out.println(fieldError.getCode());
    }

    if(object instanceof ObjectError) {
        ObjectError objectError = (ObjectError) object;

        System.out.println(objectError.getCode());
    }
}

I hope it can be useful to you

UPDATE

If you want to get the message provided by your resource bundle, you need a registered messageSource instance (It must be called messageSource)

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames" value="ValidationMessages"/>
</bean>

Inject your MessageSource instance inside your View

@Autowired
private MessageSource messageSource;

And to get your message, do as follows

for (Object object : bindingResult.getAllErrors()) {
    if(object instanceof FieldError) {
        FieldError fieldError = (FieldError) object;

        /**
          * Use null as second parameter if you do not use i18n (internationalization)
          */

        String message = messageSource.getMessage(fieldError, null);
    }
}

Your Validator should looks like

/**
  * Use null as fourth parameter if you do not want a default message
  */
errors.rejectValue("<FIELD_NAME_GOES_HERE>", "answerform.questionId.invalid", new Object [] {"123"}, null);