Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add JsonRpcReference annotation #317

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.googlecode.jsonrpc4j.spring;

import com.googlecode.jsonrpc4j.JsonRpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.ReflectionUtils;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;


public class AutoJsonRpcClientProxyFactory implements ApplicationContextAware, InstantiationAwareBeanPostProcessor {

private static final Logger logger = LoggerFactory.getLogger(AutoJsonRpcClientProxyFactory.class);

private ApplicationContext applicationContext;

private URL baseUrl;

@Override
public boolean postProcessAfterInstantiation(final Object bean, final String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), field -> {
if (field.isAnnotationPresent(JsonRpcReference.class)) {
// valid
final Class serviceInterface = field.getType();
if (!serviceInterface.isInterface()) {
throw new RuntimeException("JsonRpcReference must be interface.");
}

JsonRpcReference rpcReference = field.getAnnotation(JsonRpcReference.class);
String fullUrl = fullUrl(rpcReference.address(), serviceInterface);
JsonProxyFactoryBean factoryBean = createJsonBean(serviceInterface, fullUrl);
factoryBean.afterPropertiesSet();
// get proxy
Object proxy = null;
try {
proxy = factoryBean.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
// set bean
field.setAccessible(true);
field.set(bean, proxy);
logger.debug("------------- set bean {} field {} to proxy {}", beanName, field.getName(), proxy.getClass().getName());
}
});
return true;
}

private String fullUrl(String url, Class serviceInterface) {
try {
baseUrl = new URL(url);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(applicationContext);
MetadataReader metadataReader = null;
try {
metadataReader = metadataReaderFactory.getMetadataReader(serviceInterface.getName());
} catch (IOException e) {
throw new RuntimeException(e);
}
ClassMetadata classMetadata = metadataReader.getClassMetadata();
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
String jsonRpcPathAnnotation = JsonRpcService.class.getName();
if (annotationMetadata.isAnnotated(jsonRpcPathAnnotation)) {
String className = classMetadata.getClassName();
String path = (String) annotationMetadata.getAnnotationAttributes(jsonRpcPathAnnotation).get("value");
logger.debug("Found JSON-RPC service to proxy [{}] on path '{}'.", className, path);
return appendBasePath(path);
} else {
throw new RuntimeException("JsonRpcService must be interface.");
}

}

private String appendBasePath(String path) {
try {
return new URL(baseUrl, path).toString();
} catch (MalformedURLException e) {
throw new IllegalArgumentException(String.format("Cannot combine URLs '%s' and '%s' to valid URL.", baseUrl, path), e);
}
}


private JsonProxyFactoryBean createJsonBean(Class serviceInterface, String serviceUrl) {
JsonProxyFactoryBean bean = new JsonProxyFactoryBean();
bean.setServiceInterface(serviceInterface);
bean.setServiceUrl(serviceUrl);
return bean;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.googlecode.jsonrpc4j.spring;

import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface JsonRpcReference {

String address() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.googlecode.jsonrpc4j.spring;

import com.googlecode.jsonrpc4j.spring.serviceb.Temperature;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.support.AopUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:clientApplicationContextB.xml")
public class JsonRpcPathClientIntegrationTestB {

@JsonRpcReference(address = "http://localhost:8080")
private Temperature temperature;

public Integer demo() {
return temperature.currentTemperature();
}


@Test
public void shouldCreateServiceExporter() {
assertNotNull(temperature);
assertTrue(AopUtils.isAopProxy(temperature));
}

@Test
public void callToObjectMethodsShouldBeHandledLocally() {
if (temperature != null) {
assertNotNull(temperature.toString());
// noinspection ResultOfMethodCallIgnored
temperature.hashCode();
// noinspection EqualsWithItself
assertTrue(temperature.equals(temperature));
}
}
}
6 changes: 6 additions & 0 deletions src/test/resources/clientApplicationContextB.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean class="com.googlecode.jsonrpc4j.spring.AutoJsonRpcClientProxyFactory"/>
</beans>