Skip to content

Commit

Permalink
#241 - all classes were regarded as Spring plugins (missing isCandida…
Browse files Browse the repository at this point in the history
…te())
  • Loading branch information
Jiří Bubník committed May 4, 2018
1 parent eaffc83 commit 91abb3c
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public ReflectionCommand(Object plugin, String className, String methodName) {
*/
public ReflectionCommand(Object target, String methodName, Object... params) {
this.target = target;
this.className = target == null ? "NULL" : target.getClass().getName();
this.methodName = methodName;
this.params = Arrays.asList(params);
}
Expand Down Expand Up @@ -208,9 +209,9 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
int result = target != null ? target.hashCode() : 0;
result = 31 * result + className.hashCode();
result = 31 * result + methodName.hashCode();
result = 31 * result + params.hashCode();
result = 31 * result + (className != null ? className.hashCode() : 0);
result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
result = 31 * result + (params != null ? params.hashCode() : 0);
result = 31 * result + (plugin != null ? plugin.hashCode() : 0);
result = 31 * result + (targetClassLoader != null ? targetClassLoader.hashCode() : 0);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ public static void refreshClass(String basePackage, byte[] classDefinition) thro
}

BeanDefinition beanDefinition = scannerAgent.resolveBeanDefinition(classDefinition);
scannerAgent.defineBean(beanDefinition);
if (beanDefinition != null) {
scannerAgent.defineBean(beanDefinition);
}

reloadFlag = false;
}
Expand All @@ -141,9 +143,11 @@ public static void refreshClass(String basePackage, byte[] classDefinition) thro
*/
public void defineBean(BeanDefinition candidate) {
synchronized (getClass()) { // TODO sychronize on DefaultListableFactory.beanDefinitionMap?

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, registry);

if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
Expand All @@ -152,18 +156,24 @@ public void defineBean(BeanDefinition candidate) {
}

removeIfExists(beanName);
if (checkCandidate(beanName, candidate)) {

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = applyScopedProxyMode(scopeMetadata, definitionHolder, registry);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder = applyScopedProxyMode(scopeMetadata, definitionHolder, registry);

LOGGER.reload("Registering Spring bean '{}'", beanName);
LOGGER.debug("Bean definition '{}'", beanName, candidate);
registerBeanDefinition(definitionHolder, registry);
LOGGER.reload("Registering Spring bean '{}'", beanName);
LOGGER.debug("Bean definition '{}'", beanName, candidate);
registerBeanDefinition(definitionHolder, registry);

freezeConfiguration();
DefaultListableBeanFactory bf = maybeRegistryToBeanFactory();
if (bf != null)
ResetRequestMappingCaches.reset(bf);

ProxyReplacer.clearAllProxies();
freezeConfiguration();
}
}

ProxyReplacer.clearAllProxies();

}

Expand Down Expand Up @@ -217,10 +227,22 @@ public BeanDefinition resolveBeanDefinition(byte[] bytes) throws IOException {
Resource resource = new ByteArrayResource(bytes);
resetCachingMetadataReaderFactoryCache();
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
return sbd;

if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
LOGGER.debug("Identified candidate component class '{}'", metadataReader.getClassMetadata().getClassName());
return sbd;
} else {
LOGGER.debug("Ignored because not a concrete top-level class '{}'", metadataReader.getClassMetadata().getClassName());
return null;
}
} else {
LOGGER.trace("Ignored because not matching any filter '{}' ", metadataReader.getClassMetadata().getClassName());
return null;
}
}

private MetadataReaderFactory getMetadataReaderFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import org.hotswap.agent.plugin.hotswapper.HotSwapper;
import org.hotswap.agent.plugin.spring.scanner.ClassPathBeanDefinitionScannerAgent;
import org.hotswap.agent.plugin.spring.scanner.XmlBeanDefinationScannerAgent;
import org.hotswap.agent.plugin.spring.testBeans.BeanPrototype;
import org.hotswap.agent.plugin.spring.testBeans.BeanRepository;
import org.hotswap.agent.plugin.spring.testBeans.BeanService;
import org.hotswap.agent.plugin.spring.testBeans.BeanServiceImpl;
import org.hotswap.agent.plugin.spring.testBeans.*;
import org.hotswap.agent.plugin.spring.testBeansHotswap.BeanPrototype2;
import org.hotswap.agent.plugin.spring.testBeansHotswap.BeanRepository2;
import org.hotswap.agent.plugin.spring.testBeansHotswap.BeanServiceImpl2;
import org.hotswap.agent.plugin.spring.testBeansHotswap.Pojo2;
import org.hotswap.agent.util.ReflectionHelper;
import org.hotswap.agent.util.spring.io.resource.ClassPathResource;
import org.hotswap.agent.util.spring.io.resource.Resource;
Expand All @@ -19,7 +17,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
Expand All @@ -45,15 +42,15 @@
public class SpringPluginTest {

@Autowired
AutowireCapableBeanFactory factory;
ApplicationContext applicationContext;

/**
* Check correct setup.
*/
@Test
public void basicTest() {
assertEquals("Hello from Repository ServiceWithAspect", factory.getBean(BeanService.class).hello());
assertEquals("Hello from Repository ServiceWithAspect Prototype", factory.getBean(BeanPrototype.class).hello());
assertEquals("Hello from Repository ServiceWithAspect", applicationContext.getBean(BeanService.class).hello());
assertEquals("Hello from Repository ServiceWithAspect Prototype", applicationContext.getBean(BeanPrototype.class).hello());
}


Expand All @@ -62,12 +59,12 @@ public void basicTest() {
*/
@Test
public void hotswapSeviceTest() throws Exception {
BeanServiceImpl bean = factory.getBean(BeanServiceImpl.class);
BeanServiceImpl bean = applicationContext.getBean(BeanServiceImpl.class);
assertEquals("Hello from Repository ServiceWithAspect", bean.hello());
swapClasses(BeanServiceImpl.class, BeanServiceImpl2.class.getName());
assertEquals("Hello from ChangedRepository Service2WithAspect", bean.hello());
// ensure that using interface is Ok as well
assertEquals("Hello from ChangedRepository Service2WithAspect", factory.getBean(BeanService.class).hello());
assertEquals("Hello from ChangedRepository Service2WithAspect", applicationContext.getBean(BeanService.class).hello());

// return configuration
swapClasses(BeanServiceImpl.class, BeanServiceImpl.class.getName());
Expand All @@ -82,22 +79,22 @@ public void hotswapSeviceTest() throws Exception {
public void hotswapSeviceAddMethodTest() throws Exception {
swapClasses(BeanServiceImpl.class, BeanServiceImpl2.class.getName());

String helloNewMethodIfaceVal = (String) ReflectionHelper.invoke(factory.getBean(BeanService.class),
String helloNewMethodIfaceVal = (String) ReflectionHelper.invoke(applicationContext.getBean(BeanService.class),
BeanServiceImpl.class, "helloNewMethod", new Class[] {});
assertEquals("Hello from helloNewMethod Service2", helloNewMethodIfaceVal);

String helloNewMethodImplVal = (String) ReflectionHelper.invoke(factory.getBean(BeanServiceImpl.class),
String helloNewMethodImplVal = (String) ReflectionHelper.invoke(applicationContext.getBean(BeanServiceImpl.class),
BeanServiceImpl.class, "helloNewMethod", new Class[] {});
assertEquals("Hello from helloNewMethod Service2", helloNewMethodImplVal);

// return configuration
swapClasses(BeanServiceImpl.class, BeanServiceImpl.class.getName());
assertEquals("Hello from Repository ServiceWithAspect", factory.getBean(BeanServiceImpl.class).hello());
assertEquals("Hello from Repository ServiceWithAspect", applicationContext.getBean(BeanServiceImpl.class).hello());
}

@Test
public void hotswapRepositoryTest() throws Exception {
BeanServiceImpl bean = factory.getBean(BeanServiceImpl.class);
BeanServiceImpl bean = applicationContext.getBean(BeanServiceImpl.class);
assertEquals("Hello from Repository ServiceWithAspect", bean.hello());
swapClasses(BeanRepository.class, BeanRepository2.class.getName());
assertEquals("Hello from ChangedRepository2 ServiceWithAspect", bean.hello());
Expand All @@ -109,47 +106,59 @@ public void hotswapRepositoryTest() throws Exception {

@Test
public void hotswapRepositoryNewMethodTest() throws Exception {
assertEquals("Hello from Repository ServiceWithAspect", factory.getBean(BeanServiceImpl.class).hello());
assertEquals("Hello from Repository ServiceWithAspect", applicationContext.getBean(BeanServiceImpl.class).hello());
swapClasses(BeanRepository.class, BeanRepository2.class.getName());

String helloNewMethodImplVal = (String) ReflectionHelper.invoke(factory.getBean("beanRepository",BeanRepository.class),
String helloNewMethodImplVal = (String) ReflectionHelper.invoke(applicationContext.getBean("beanRepository",BeanRepository.class),
BeanRepository.class, "helloNewMethod", new Class[] {});
assertEquals("Repository new method", helloNewMethodImplVal);

// return configuration
swapClasses(BeanRepository.class, BeanRepository.class.getName());
assertEquals("Hello from Repository ServiceWithAspect", factory.getBean(BeanServiceImpl.class).hello());
assertEquals("Hello from Repository ServiceWithAspect", applicationContext.getBean(BeanServiceImpl.class).hello());
}

@Test
public void hotswapPrototypeTestNewInstance() throws Exception {
assertEquals("Hello from Repository ServiceWithAspect Prototype", factory.getBean(BeanPrototype.class).hello());
assertEquals("Hello from Repository ServiceWithAspect Prototype", applicationContext.getBean(BeanPrototype.class).hello());

// swap service this prototype is dependent to
swapClasses(BeanServiceImpl.class, BeanServiceImpl2.class.getName());
assertEquals("Hello from ChangedRepository Service2WithAspect Prototype", factory.getBean(BeanPrototype.class).hello());
assertEquals("Hello from ChangedRepository Service2WithAspect Prototype", applicationContext.getBean(BeanPrototype.class).hello());

// swap autowired field
swapClasses(BeanPrototype.class, BeanPrototype2.class.getName());
assertEquals("Hello from Repository Prototype2", factory.getBean(BeanPrototype.class).hello());
assertEquals("Hello from Repository Prototype2", applicationContext.getBean(BeanPrototype.class).hello());

// return configuration
swapClasses(BeanServiceImpl.class, BeanServiceImpl.class.getName());
swapClasses(BeanPrototype.class, BeanPrototype.class.getName());
assertEquals("Hello from Repository ServiceWithAspect Prototype", factory.getBean(BeanPrototype.class).hello());
assertEquals("Hello from Repository ServiceWithAspect Prototype", applicationContext.getBean(BeanPrototype.class).hello());
}

@Test
public void hotswapPrototypeTestExistingInstance() throws Exception {
BeanPrototype beanPrototypeInstance = factory.getBean(BeanPrototype.class);
BeanPrototype beanPrototypeInstance = applicationContext.getBean(BeanPrototype.class);
assertEquals("Hello from Repository ServiceWithAspect Prototype", beanPrototypeInstance.hello());

swapClasses(BeanServiceImpl.class, BeanServiceImpl2.class.getName());
assertEquals("Hello from ChangedRepository Service2WithAspect Prototype", beanPrototypeInstance.hello());

// return configuration
swapClasses(BeanServiceImpl.class, BeanServiceImpl.class.getName());
assertEquals("Hello from Repository ServiceWithAspect Prototype", factory.getBean(BeanPrototype.class).hello());
assertEquals("Hello from Repository ServiceWithAspect Prototype", applicationContext.getBean(BeanPrototype.class).hello());
}

@Test
public void pojoTest() throws Exception {
//Pojo pojo = applicationContext.getAutowireCapableBeanFactory().createBean(Pojo.class);

assertEquals(0, applicationContext.getBeanNamesForType(Pojo.class).length);

swapClasses(Pojo.class, Pojo2.class.getName());


assertEquals(0, applicationContext.getBeanNamesForType(Pojo.class).length);
}

private void swapClasses(Class original, String swap) throws Exception {
Expand All @@ -167,7 +176,7 @@ public boolean result() throws Exception {
}


private static ApplicationContext applicationContext;
private static ApplicationContext xmlApplicationContext;
private static Resource xmlContext = new ClassPathResource("xmlContext.xml");
private static Resource xmlContextWithRepo = new ClassPathResource("xmlContextWithRepository.xml");
private static Resource xmlContextWithChangedRepo = new ClassPathResource("xmlContextWithChangedRepository.xml");
Expand All @@ -181,9 +190,9 @@ not be able to get the right registry to use (it will only use the first one it

@Before
public void initApplicationCtx() throws IOException {
if (applicationContext == null) {
if (xmlApplicationContext == null) {
writeRepositoryToXml();
applicationContext = new ClassPathXmlApplicationContext("xmlContext.xml");
xmlApplicationContext = new ClassPathXmlApplicationContext("xmlContext.xml");
}
}

Expand All @@ -203,7 +212,7 @@ private void writeChangedRepositoryToXml() throws IOException {

@Test
public void swapXmlTest() throws IOException {
BeanService beanService = applicationContext.getBean("beanService", BeanService.class);
BeanService beanService = xmlApplicationContext.getBean("beanService", BeanService.class);
Assert.assertEquals(beanService.hello(), "Hello from Repository ServiceWithAspect");

XmlBeanDefinationScannerAgent.reloadFlag = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package org.hotswap.agent.plugin.spring.testBeans;

public class Pojo {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.hotswap.agent.plugin.spring.testBeansHotswap;

public class Pojo2 {
public void test() { }
}

0 comments on commit 91abb3c

Please sign in to comment.