How does class gets injected which implements interface method being called in Java or Groovy code?

Viewed 296

I have below working groovy code from Spring framework project:

import org.springframework.oxm.Unmarshaller

public class ItemSearchService  {
    Unmarshaller unmarshaller;
    public ItemSearchResponse getObject(InputStream xml) {
    
        ItemSearchResponse its = null;
        try {
            its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
        } finally {
        }
        return its;
    }
}

Unmarshaller.unmarshall is actually interface method: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Unmarshaller.html

Unmarshaller interface is implemented by several classes.

Who decides which implementing class to inject during runtime and how it decides which class to use?

Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?

Also how to know which implementing class it actually used?

Will above code work outside of Spring in ordinary Java file assuming dependent jars in classpath?

2 Answers

As soon as it goes about a Grails project (not a pure Spring one), some things should be clarified.

Who decides which implementing class to inject during runtime and how it decides which class to use? Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?

What Spring does in a plain Spring(Boot) is nicely described by @svr s answer and other documentation on the Internet, but has not much to do with your case.

In Grails the convention-over-configuration doctrine is used, meaning that

  • by default Bean Autowiring is active
  • only beans which are declared as Grails artefacts, like Service are auto-injected.

Usually, if you want to autowire a bean of other stereotype, you have to declare it somewhere, otherwise Spring IoC container inside Grails simply won't find it.

You shall check your grails-app/conf/spring folder for resources.groovy (or maybe yaml or xml files depending on version ) and see if your unmarshaller bean is defined there. It should look like:

beans = {
  unmarshaller Unmarshaller ....
}

So, basically it doesn't matter how many implementations of Unmarshaller interface are present in all project's jar files. The only thing what matters is what defined in your resources.groovy.

If you want to check the class of the bean in runtime, just log it's class in your service:

class ItemSearchService  {
  Unmarshaller unmarshaller
  ItemSearchResponse getObject(InputStream xml) {
     log.info "unmarshaller's class is $unmarshaller.class"
     // or
     // println "unmarshaller's class is $unmarshaller.class"
  }
}  

Who decides which implementing class to inject during runtime and how it decides which class to use? Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?

Yes Spring IOC container. It happens at run time when the application is run.

Also how to know which implementing class it actually used?

For most part you will have to define bean with implementation to pick. For other cases you can look at the spring auto configuration classes.

Will above code work outside of Spring in ordinary Java file assuming dependent jars in classpath?

Not sure what you mean outside of Spring but as long as application is packaged correctly it should all work.

Quick Overview

Spring IOC will only inject a bean when found in the application context. An application context loosely is repository of beans.

Classpath Scanning and Registration

Spring scans application to pick up all the stereotyped classes and registers bean definition with application context. Stereotyped annotations include @Component, @Repository, @Service, @Controller, @Configuration. More

Dependency Injection

Spring DI creates the bean and injects them as dependencies into application. You can create dependencies between different application components using the registered beans and spring will autowire these for you. More. There are two types of DI - Constructor based and setter based - Constructor for required dependencies and setter based for optional dependencies. More

There are sensible defaults provided when you use any spring classes. You just have to define the bean where there is no default or you would like to pick different implementation. Application context can be further be enriched by using Spring Boot Auto Configuration where all related classes are wired together to form a coherent entry classes. You can then easily inject these into application for getting started. More

Example

You can define bean in the @Configuration class for a web service module.

@Configuration
public class WSConfig {
   @Bean
   public Jaxb2Marshaller marshaller() {
      Jaxb2Marshaller marsharller = new Jaxb2Marshaller();
      marsharller.setContextPath("some package");
   }

   @Bean
   public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marsharller) {         
      WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marsharller);
   }
}

@RequiredArgsConstructur
public class ItemSearchService  {
    private final Unmarshaller unmarshaller;
    public ItemSearchResponse getObject(InputStream xml) {
       ItemSearchResponse its = null;
       try {
        its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
        } finally {}
       return its;
    }
 }

This similar configuration is automatically taken care by WebServicesAutoConfiguration with ways to customize when using Spring Boot.

Related