diff --git a/spring-core/pom.xml b/spring-core/pom.xml
index 84a492bbe4..bf8c8f3ebc 100644
--- a/spring-core/pom.xml
+++ b/spring-core/pom.xml
@@ -47,6 +47,11 @@
4.12
test
+
+ com.google.guava
+ guava
+ 20.0
+
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/FactoryBeanAppConfig.java b/spring-core/src/main/java/com/baeldung/factorybean/FactoryBeanAppConfig.java
new file mode 100644
index 0000000000..ab36df27cb
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/FactoryBeanAppConfig.java
@@ -0,0 +1,25 @@
+package com.baeldung.factorybean;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FactoryBeanAppConfig {
+ @Bean
+ public ToolFactory tool() {
+ ToolFactory factory = new ToolFactory();
+ factory.setFactoryId(7070);
+ factory.setToolId(2);
+ factory.setToolName("wrench");
+ factory.setToolPrice(3.7);
+ return factory;
+ }
+
+ @Bean
+ public Worker worker() throws Exception {
+ Worker worker = new Worker();
+ worker.setNumber("1002");
+ worker.setTool(tool().getObject());
+ return worker;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/InitializationToolFactory.java b/spring-core/src/main/java/com/baeldung/factorybean/InitializationToolFactory.java
new file mode 100644
index 0000000000..6d2fd2564e
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/InitializationToolFactory.java
@@ -0,0 +1,67 @@
+package com.baeldung.factorybean;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.StringUtils;
+
+public class InitializationToolFactory implements FactoryBean, InitializingBean {
+ private int factoryId;
+ private int toolId;
+ private String toolName;
+ private double toolPrice;
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ checkArgument(!StringUtils.isEmpty(toolName), "tool name cannot be empty");
+ checkArgument(toolPrice >= 0, "tool price should not be less than 0");
+ }
+
+ @Override
+ public Tool getObject() throws Exception {
+ return new Tool(toolId, toolName, toolPrice);
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return Tool.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return false;
+ }
+
+ public int getFactoryId() {
+ return factoryId;
+ }
+
+ public void setFactoryId(int factoryId) {
+ this.factoryId = factoryId;
+ }
+
+ public int getToolId() {
+ return toolId;
+ }
+
+ public void setToolId(int toolId) {
+ this.toolId = toolId;
+ }
+
+ public String getToolName() {
+ return toolName;
+ }
+
+ public void setToolName(String toolName) {
+ this.toolName = toolName;
+ }
+
+ public double getToolPrice() {
+ return toolPrice;
+ }
+
+ public void setToolPrice(double toolPrice) {
+ this.toolPrice = toolPrice;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/NonSingleToolFactory.java b/spring-core/src/main/java/com/baeldung/factorybean/NonSingleToolFactory.java
new file mode 100644
index 0000000000..c818b775eb
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/NonSingleToolFactory.java
@@ -0,0 +1,56 @@
+package com.baeldung.factorybean;
+
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+public class NonSingleToolFactory extends AbstractFactoryBean {
+ private int factoryId;
+ private int toolId;
+ private String toolName;
+ private double toolPrice;
+
+ public NonSingleToolFactory() {
+ setSingleton(false);
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return Tool.class;
+ }
+
+ @Override
+ protected Tool createInstance() throws Exception {
+ return new Tool(toolId, toolName, toolPrice);
+ }
+
+ public int getFactoryId() {
+ return factoryId;
+ }
+
+ public void setFactoryId(int factoryId) {
+ this.factoryId = factoryId;
+ }
+
+ public int getToolId() {
+ return toolId;
+ }
+
+ public void setToolId(int toolId) {
+ this.toolId = toolId;
+ }
+
+ public String getToolName() {
+ return toolName;
+ }
+
+ public void setToolName(String toolName) {
+ this.toolName = toolName;
+ }
+
+ public double getToolPrice() {
+ return toolPrice;
+ }
+
+ public void setToolPrice(double toolPrice) {
+ this.toolPrice = toolPrice;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/PostConstructToolFactory.java b/spring-core/src/main/java/com/baeldung/factorybean/PostConstructToolFactory.java
new file mode 100644
index 0000000000..47db05d271
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/PostConstructToolFactory.java
@@ -0,0 +1,68 @@
+package com.baeldung.factorybean;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.util.StringUtils;
+
+public class PostConstructToolFactory implements FactoryBean {
+ private int factoryId;
+ private int toolId;
+ private String toolName;
+ private double toolPrice;
+
+ @Override
+ public Tool getObject() throws Exception {
+ return new Tool(toolId, toolName, toolPrice);
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return Tool.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return false;
+ }
+
+ @PostConstruct
+ public void checkParams() {
+ checkArgument(!StringUtils.isEmpty(toolName), "tool name cannot be empty");
+ checkArgument(toolPrice >= 0, "tool price should not be less than 0");
+ }
+
+ public int getFactoryId() {
+ return factoryId;
+ }
+
+ public void setFactoryId(int factoryId) {
+ this.factoryId = factoryId;
+ }
+
+ public int getToolId() {
+ return toolId;
+ }
+
+ public void setToolId(int toolId) {
+ this.toolId = toolId;
+ }
+
+ public String getToolName() {
+ return toolName;
+ }
+
+ public void setToolName(String toolName) {
+ this.toolName = toolName;
+ }
+
+ public double getToolPrice() {
+ return toolPrice;
+ }
+
+ public void setToolPrice(double toolPrice) {
+ this.toolPrice = toolPrice;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/SingleToolFactory.java b/spring-core/src/main/java/com/baeldung/factorybean/SingleToolFactory.java
new file mode 100644
index 0000000000..bc0c2d79c0
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/SingleToolFactory.java
@@ -0,0 +1,53 @@
+package com.baeldung.factorybean;
+
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+//no need to set singleton property because default value is true
+public class SingleToolFactory extends AbstractFactoryBean {
+ private int factoryId;
+ private int toolId;
+ private String toolName;
+ private double toolPrice;
+
+ @Override
+ public Class> getObjectType() {
+ return Tool.class;
+ }
+
+ @Override
+ protected Tool createInstance() throws Exception {
+ return new Tool(toolId, toolName, toolPrice);
+ }
+
+ public int getFactoryId() {
+ return factoryId;
+ }
+
+ public void setFactoryId(int factoryId) {
+ this.factoryId = factoryId;
+ }
+
+ public int getToolId() {
+ return toolId;
+ }
+
+ public void setToolId(int toolId) {
+ this.toolId = toolId;
+ }
+
+ public String getToolName() {
+ return toolName;
+ }
+
+ public void setToolName(String toolName) {
+ this.toolName = toolName;
+ }
+
+ public double getToolPrice() {
+ return toolPrice;
+ }
+
+ public void setToolPrice(double toolPrice) {
+ this.toolPrice = toolPrice;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/Tool.java b/spring-core/src/main/java/com/baeldung/factorybean/Tool.java
new file mode 100644
index 0000000000..a7f7f7681e
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/Tool.java
@@ -0,0 +1,40 @@
+package com.baeldung.factorybean;
+
+public class Tool {
+ private int id;
+ private String name;
+ private double price;
+
+ public Tool() {
+ }
+
+ public Tool(int id, String name, double price) {
+ this.id = id;
+ this.name = name;
+ this.price = price;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/ToolFactory.java b/spring-core/src/main/java/com/baeldung/factorybean/ToolFactory.java
new file mode 100644
index 0000000000..ca8f82eadb
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/ToolFactory.java
@@ -0,0 +1,57 @@
+package com.baeldung.factorybean;
+
+import org.springframework.beans.factory.FactoryBean;
+
+public class ToolFactory implements FactoryBean {
+ private int factoryId;
+ private int toolId;
+ private String toolName;
+ private double toolPrice;
+
+ @Override
+ public Tool getObject() throws Exception {
+ return new Tool(toolId, toolName, toolPrice);
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return Tool.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return false;
+ }
+
+ public int getFactoryId() {
+ return factoryId;
+ }
+
+ public void setFactoryId(int factoryId) {
+ this.factoryId = factoryId;
+ }
+
+ public int getToolId() {
+ return toolId;
+ }
+
+ public void setToolId(int toolId) {
+ this.toolId = toolId;
+ }
+
+ public String getToolName() {
+ return toolName;
+ }
+
+ public void setToolName(String toolName) {
+ this.toolName = toolName;
+ }
+
+ public double getToolPrice() {
+ return toolPrice;
+ }
+
+ public void setToolPrice(double toolPrice) {
+ this.toolPrice = toolPrice;
+ }
+}
diff --git a/spring-core/src/main/java/com/baeldung/factorybean/Worker.java b/spring-core/src/main/java/com/baeldung/factorybean/Worker.java
new file mode 100644
index 0000000000..9a35c0656b
--- /dev/null
+++ b/spring-core/src/main/java/com/baeldung/factorybean/Worker.java
@@ -0,0 +1,30 @@
+package com.baeldung.factorybean;
+
+public class Worker {
+ private String number;
+ private Tool tool;
+
+ public Worker() {
+ }
+
+ public Worker(String number, Tool tool) {
+ this.number = number;
+ this.tool = tool;
+ }
+
+ public String getNumber() {
+ return number;
+ }
+
+ public void setNumber(String number) {
+ this.number = number;
+ }
+
+ public Tool getTool() {
+ return tool;
+ }
+
+ public void setTool(Tool tool) {
+ this.tool = tool;
+ }
+}
diff --git a/spring-core/src/main/resources/factorybean-abstract-spring-ctx.xml b/spring-core/src/main/resources/factorybean-abstract-spring-ctx.xml
new file mode 100644
index 0000000000..6bce114d9c
--- /dev/null
+++ b/spring-core/src/main/resources/factorybean-abstract-spring-ctx.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core/src/main/resources/factorybean-init-spring-ctx.xml b/spring-core/src/main/resources/factorybean-init-spring-ctx.xml
new file mode 100644
index 0000000000..47722b6d3d
--- /dev/null
+++ b/spring-core/src/main/resources/factorybean-init-spring-ctx.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core/src/main/resources/factorybean-postconstruct-spring-ctx.xml b/spring-core/src/main/resources/factorybean-postconstruct-spring-ctx.xml
new file mode 100644
index 0000000000..94a4f407a8
--- /dev/null
+++ b/spring-core/src/main/resources/factorybean-postconstruct-spring-ctx.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core/src/main/resources/factorybean-spring-ctx.xml b/spring-core/src/main/resources/factorybean-spring-ctx.xml
new file mode 100644
index 0000000000..ab0c646bb0
--- /dev/null
+++ b/spring-core/src/main/resources/factorybean-spring-ctx.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core/src/test/java/com/baeldung/factorybean/AbstractFactoryBeanTest.java b/spring-core/src/test/java/com/baeldung/factorybean/AbstractFactoryBeanTest.java
new file mode 100644
index 0000000000..790107f114
--- /dev/null
+++ b/spring-core/src/test/java/com/baeldung/factorybean/AbstractFactoryBeanTest.java
@@ -0,0 +1,35 @@
+package com.baeldung.factorybean;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class AbstractFactoryBeanTest {
+ @Test
+ public void testSingleToolFactory() {
+ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:factorybean-abstract-spring-ctx.xml");
+
+ Worker worker1 = (Worker) context.getBean("worker1");
+ Worker worker2 = (Worker) context.getBean("worker2");
+
+ assertThat(worker1.getNumber(), equalTo("50001"));
+ assertThat(worker2.getNumber(), equalTo("50002"));
+ assertTrue(worker1.getTool() == worker2.getTool());
+ }
+
+ @Test
+ public void testNonSingleToolFactory() {
+ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:factorybean-abstract-spring-ctx.xml");
+
+ Worker worker3 = (Worker) context.getBean("worker3");
+ Worker worker4 = (Worker) context.getBean("worker4");
+
+ assertThat(worker3.getNumber(), equalTo("50003"));
+ assertThat(worker4.getNumber(), equalTo("50004"));
+ assertTrue(worker3.getTool() != worker4.getTool());
+ }
+}
diff --git a/spring-core/src/test/java/com/baeldung/factorybean/FactoryBeanInitializeTest.java b/spring-core/src/test/java/com/baeldung/factorybean/FactoryBeanInitializeTest.java
new file mode 100644
index 0000000000..673bab6f63
--- /dev/null
+++ b/spring-core/src/test/java/com/baeldung/factorybean/FactoryBeanInitializeTest.java
@@ -0,0 +1,17 @@
+package com.baeldung.factorybean;
+
+import org.junit.Test;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class FactoryBeanInitializeTest {
+ @Test(expected = BeanCreationException.class)
+ public void testInitializationToolFactory() {
+ new ClassPathXmlApplicationContext("classpath:factorybean-init-spring-ctx.xml");
+ }
+
+ @Test(expected = BeanCreationException.class)
+ public void testPostConstructToolFactory() {
+ new ClassPathXmlApplicationContext("classpath:factorybean-postconstruct-spring-ctx.xml");
+ }
+}
diff --git a/spring-core/src/test/java/com/baeldung/factorybean/FactoryBeanTest.java b/spring-core/src/test/java/com/baeldung/factorybean/FactoryBeanTest.java
new file mode 100644
index 0000000000..d06448b63c
--- /dev/null
+++ b/spring-core/src/test/java/com/baeldung/factorybean/FactoryBeanTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.factorybean;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class FactoryBeanTest {
+ @Test
+ public void testConstructWorkerByXml() {
+ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:factorybean-spring-ctx.xml");
+
+ Worker worker = (Worker) context.getBean("worker");
+ assertThat(worker.getNumber(), equalTo("1001"));
+ assertThat(worker.getTool().getId(), equalTo(1));
+ assertThat(worker.getTool().getName(), equalTo("screwdriver"));
+ assertThat(worker.getTool().getPrice(), equalTo(1.5));
+
+ ToolFactory toolFactory = (ToolFactory) context.getBean("&tool");
+ assertThat(toolFactory.getFactoryId(), equalTo(9090));
+ }
+
+ @Test
+ public void testConstructWorkerByJava() {
+ ApplicationContext context = new AnnotationConfigApplicationContext(FactoryBeanAppConfig.class);
+
+ Worker worker = (Worker) context.getBean("worker");
+ assertThat(worker.getNumber(), equalTo("1002"));
+ assertThat(worker.getTool().getId(), equalTo(2));
+ assertThat(worker.getTool().getName(), equalTo("wrench"));
+ assertThat(worker.getTool().getPrice(), equalTo(3.7));
+
+ ToolFactory toolFactory = (ToolFactory) context.getBean("&tool");
+ assertThat(toolFactory.getFactoryId(), equalTo(7070));
+ }
+}