Spring Auto-wiring and interact with other POJOs
Tags: programming, java, tutorial
Published: 2022-01-12 08:40:56

In this tutorial, I'm going to cover how to interact with internal POJOs (Plain Old Java Objects) in spring application. Also I'm going to cover why spring need auto-wiring between two POJOs. 

## How it works

Sometime the POJO instances or beans need to refer another POJO instance to complete application's functionality (i.e. a POJO instance is dependent on another POJO instance). To access a POJO inside another POJO, we need to specify the bean reference inside the configuration file. Often, this dependency need to handle manually by programmers. But, in large commercial application, we need a more reliable way to resolve this inner dependency. That's where spring auto-wiring comes in place.

By auto-wiring, spring container establish a relationship between two POJO instances. By enebeling auto-wiring, we let spring to resolve collabration between beans automatically. Thus autowiring can be especially useful during development, without negating the option of switching to explicit wiring when the code base becomes more stable.

The autowiring functionality has four modes. They are-

|**Mode**|**Explanation**|
|-|-|
|`no`|(Default) No auto-wiring. Bean references must be defined by ref elements. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system.|
|`byName`|Auto-wiring by property name. Spring looks for a bean with the same name as the property that needs to be auto-wired. For example, if a bean definition is set to auto-wire by name and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master and uses it to set the property.|
|`byType`|Lets a property be auto-wired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType auto-wiring for that bean. If there are no matching beans, nothing happens (the property is not set).|
|`constructor`|Analogous to byType but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised.|

## Program structure

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3gxvgw7p8l8lu79965t.png)

Github repository link: [click here](https://github.com/suvasish114/SpringAutowire)

## Program logic

Let's create a java class named `Laptop` having four local variable, `name`, `price`, `motherboard`, `processor`. motherboard is an object of `Motherboard` class and processor is an object of `Processor` class.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ve20urwmbmpe14uvqvbr.png) 

So, we can clearly see that, `Laptop` class has inner dependency on `Motherboard` and `Processor` class. In normal programming approach, we need to declare each of dependent object with `new` operator. But, whenever we use `new` to declare object, we are hardcoding the value (the program will have tight coupling). So, we are going to resolve this problem by declaring POJO instances. Now, we don't need to hardcoding values inside our program logic.

```java
// Filename: Laptop.java
package com.example.SpringAutowire;

public class Laptop {
	private String name;
	private int price;
	private Motherboard motherboard;
	private Processor processor;
	
	// constructors
	public Laptop() {}
	public String getName() {
		return name;
	}

        // getters and setters
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public Motherboard getMotherboard() {
		return motherboard;
	}
	public void setMotherboard(Motherboard motherboard) {
		this.motherboard = motherboard;
	}
	public Processor getProcessor() {
		return processor;
	}
	public void setProcessor(Processor processor) {
		this.processor = processor;
	}
	public void getLaptopDetails() {
		System.out.println("Laptop Name: "+name);
		System.out.println("Laptop price: "+price);
		System.out.println("Motherboard: "+motherboard.getName());
		System.out.println("Processor: "+processor.getName());
	}
}
```
```java
// Filename: Motherboard.java
package com.example.SpringAutowire;
public class Motherboard {
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
```
```java
// Filename: Processor.java
package com.example.SpringAutowire;
public class Processor {
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
```

Now, It's time to define POJO instances for the above java classes. To do this, I'm going to create a `.xml` file named `Beans.xml` inside my application root class-path.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd"></beans>
```

Now, inside those `<beans>` `</beans>` tag, we are going to define our individual POJO instances, with some values.

```xml
	<bean id="laptop" class="com.example.SpringAutowire.Laptop">
		<property name="name" value="dell vostro 1450s"/>
		<property name="price" value="45000"/>
		<property name="motherboard" ref="motherboard"/>
		<property name="processor" ref="processor"/>
	</bean>
	<bean id="processor" class="com.example.SpringAutowire.Processor">
		<property name="name" value="intel i3 11g"/>
	</bean>
	<bean id="motherboard" class="com.example.SpringAutowire.Motherboard">
		<property name="name" value="gigabyte h81ms v2"/>
	</bean>
```

Note that inside laptop bean, the value of `motherboard` and `processor` is referencing (`ref` attribute inside `property` tag refer to another POJO. It's not mandatory to place the POJO instances inside same xml file) to another POJO instances, which are declared after `laptop` POJO. By doing this, we have resolve internal POJO dependency. Now, if you run your application (with driving code), it will work successfully.

## Autowiring POJOs

So far we resolve internal POJO dependency. But, still we writing POJO dependency by ourself manually. By using `autowire` attribute inside a `<bean>` tag, we let spring to automatically fetch the internal beans.

```xml
	<bean id="laptop" class="com.example.SpringAutowire.Laptop" autowire="byName">
		<property name="name" value="dell vostro 1450s"/>
		<property name="price" value="45000"/>
	</bean>
```
Note that, now laptop no longer has `processor` and `motherboard` value defined. By define `autowire="byName"`, srping will search for the required beans by its name, and whenever match found, spring will automatically refer the bean at compile time.

## Driving code

Now, we are ready to write our final pice of code or the driving code. Now create a java class containing the main method(if you create your project using maven or groovy project template, you are provided a java class containing main mathod, just use those file).

Inside those class declare a `ApplicationContext` variable and
define with `ClassPathXmlApplicationContext()` with parameter the string representation of your configuration xml file name with fully specified path (in my case, my xml file is placed at the root location, so I no need to enter the fully specified path name). Make sure that this variable is declared as static, so that we can access it from main method.

The `ApplicationContext` interface is responsible to create the spring IOC container(if you are not familiar with IOC, [click here](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-autowire) and go through the documentation). `ClassPathXmlApplicationContext` class is a subclass which implemented `ApplicationContext` interface. There are many other subclass available to create IOC container.

Now, inside the main method of our code, create a variable of type Laptop and instantiated it with a defined bean. In this case `context.getBean("laptop", Laptop.class)` return a variable of type `Laptop`. The first argument of getBean refers to the bean name as string and the second argument refers to the actual class. By default `getBean()` method's return type is `java.lang.Object`. The second argument in the `getBean()` method actually used to typecast the value. So we no need to typecast it manually. In the below code, I'm typecasting the value to `Laptop.class` type.

```java
package com.example.SpringAutowire;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
	private static ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    public static void main( String[] args ){
       Laptop laptop = context.getBean("laptop", Laptop.class);
       laptop.getLaptopDetails();
    }
}
```

## Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5kgy1nvkhxewiukjpilx.png)