/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.annotation;

import org.junit.Before;
import org.junit.Test;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.tests.sample.beans.TestBean;

import static org.junit.Assert.*;

/**
 * @author Karl Pietrzak
 * @author Juergen Hoeller
 */
public class LookupAnnotationTests {

	private DefaultListableBeanFactory beanFactory;


	@Before
	public void setUp() {
		beanFactory = new DefaultListableBeanFactory();
		AutowiredAnnotationBeanPostProcessor aabpp = new AutowiredAnnotationBeanPostProcessor();
		aabpp.setBeanFactory(beanFactory);
		beanFactory.addBeanPostProcessor(aabpp);
		beanFactory.registerBeanDefinition("abstractBean", new RootBeanDefinition(AbstractBean.class));
		RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class);
		tbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
		beanFactory.registerBeanDefinition("testBean", tbd);
	}


	@Test
	public void testWithoutConstructorArg() {
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
		assertNotNull(bean);
		Object expected = bean.get();
		assertEquals(TestBean.class, expected.getClass());
	}

	@Test
	public void testWithOverloadedArg() {
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
		assertNotNull(bean);
		TestBean expected = bean.get("haha");
		assertEquals(TestBean.class, expected.getClass());
		assertEquals("haha", expected.getName());
	}

	@Test
	public void testWithOneConstructorArg() {
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
		assertNotNull(bean);
		TestBean expected = bean.getOneArgument("haha");
		assertEquals(TestBean.class, expected.getClass());
		assertEquals("haha", expected.getName());
	}

	@Test
	public void testWithTwoConstructorArg() {
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
		assertNotNull(bean);
		TestBean expected = bean.getTwoArguments("haha", 72);
		assertEquals(TestBean.class, expected.getClass());
		assertEquals("haha", expected.getName());
		assertEquals(72, expected.getAge());
	}

	@Test
	public void testWithThreeArgsShouldFail() {
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
		assertNotNull(bean);
		try {
			bean.getThreeArguments("name", 1, 2);
			fail("TestBean does not have a three arg constructor so this should not have worked");
		}
		catch (AbstractMethodError ex) {
		}
	}


	public static abstract class AbstractBean {

		@Lookup
		public abstract TestBean get();

		@Lookup
		public abstract TestBean get(String name);  // overloaded

		@Lookup
		public abstract TestBean getOneArgument(String name);

		@Lookup
		public abstract TestBean getTwoArguments(String name, int age);

		public abstract TestBean getThreeArguments(String name, int age, int anotherArg);
	}

}

@@ -21,9 +21,9 @@
 -201
-4
+6
  the
@@ -1457,16 +1457,114 @@
 lass));%0A
+%09%09beanFactory.registerBeanDefinition(%22beanConsumer%22, new RootBeanDefinition(BeanConsumer.class));%0A
 %09%09RootBe
@@ -1962,24 +1962,98 @@
 etClass());%0A
+%09%09assertSame(bean, beanFactory.getBean(BeanConsumer.class).abstractBean);%0A
 %09%7D%0A%0A%09@Test%0A%09
@@ -2316,32 +2316,106 @@
 ted.getName());%0A
+%09%09assertSame(bean, beanFactory.getBean(BeanConsumer.class).abstractBean);%0A
 %09%7D%0A%0A%09@Test%0A%09publ
@@ -2693,24 +2693,98 @@
 getName());%0A
+%09%09assertSame(bean, beanFactory.getBean(BeanConsumer.class).abstractBean);%0A
 %09%7D%0A%0A%09@Test%0A%09
@@ -3114,16 +3114,90 @@
 Age());%0A
+%09%09assertSame(bean, beanFactory.getBean(BeanConsumer.class).abstractBean);%0A
 %09%7D%0A%0A%09@Te
@@ -3523,16 +3523,415 @@
 ) %7B%0A%09%09%7D%0A
+%09%09assertSame(bean, beanFactory.getBean(BeanConsumer.class).abstractBean);%0A%09%7D%0A%0A%09@Test%0A%09public void testWithEarlyInjection() %7B%0A%09%09AbstractBean bean = beanFactory.getBean(%22beanConsumer%22, BeanConsumer.class).abstractBean;%0A%09%09assertNotNull(bean);%0A%09%09Object expected = bean.get();%0A%09%09assertEquals(TestBean.class, expected.getClass());%0A%09%09assertSame(bean, beanFactory.getBean(BeanConsumer.class).abstractBean);%0A
 %09%7D%0A%0A%0A%09pu
@@ -4233,16 +4233,16 @@
  age);%0A%0A
-
 %09%09public
@@ -4321,10 +4321,94 @@
 g);%0A%09%7D%0A%0A
+%0A%09public static class BeanConsumer %7B%0A%0A%09%09@Autowired%0A%09%09AbstractBean abstractBean;%0A%09%7D%0A%0A
 %7D%0A

Test injection for @Lookup-declaring bean