Skip to content

Commit

Permalink
Merge pull request #249 from Dog-Lee/master
Browse files Browse the repository at this point in the history
@JsonRpcService support placeholder
  • Loading branch information
briandilley authored Jan 27, 2021
2 parents 96e0e51 + d438415 commit 5abebf3
Showing 1 changed file with 134 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -1,124 +1,134 @@
package com.googlecode.jsonrpc4j.spring;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.googlecode.jsonrpc4j.JsonRpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
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 java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import static java.lang.String.format;
import static org.springframework.util.ClassUtils.convertClassNameToResourcePath;
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;

/**
* Auto-creates proxies for service interfaces annotated with {@link JsonRpcService}.
*/
@SuppressWarnings("unused")
public class AutoJsonRpcClientProxyCreator implements BeanFactoryPostProcessor, ApplicationContextAware {

private static final Logger logger = LoggerFactory.getLogger(AutoJsonRpcClientProxyCreator.class);
private ApplicationContext applicationContext;
private String scanPackage;
private URL baseUrl;
private ObjectMapper objectMapper;
private String contentType;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(applicationContext);
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
String resolvedPath = resolvePackageToScan();
logger.debug("Scanning '{}' for JSON-RPC service interfaces.", resolvedPath);
try {
for (Resource resource : applicationContext.getResources(resolvedPath)) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
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);
registerJsonProxyBean(defaultListableBeanFactory, className, path);
}
}
}
} catch (IOException e) {
throw new IllegalStateException(format("Cannot scan package '%s' for classes.", resolvedPath), e);
}
}

/**
* Converts the scanPackage to something that the resource loader can handleRequest.
*/
private String resolvePackageToScan() {
return CLASSPATH_URL_PREFIX + convertClassNameToResourcePath(scanPackage) + "/**/*.class";
}

/**
* Registers a new proxy bean with the bean factory.
*/
private void registerJsonProxyBean(DefaultListableBeanFactory defaultListableBeanFactory, String className, String path) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(JsonProxyFactoryBean.class)
.addPropertyValue("serviceUrl", appendBasePath(path))
.addPropertyValue("serviceInterface", className);

if (objectMapper != null) {
beanDefinitionBuilder.addPropertyValue("objectMapper", objectMapper);
}

if (contentType != null) {
beanDefinitionBuilder.addPropertyValue("contentType", contentType);
}

defaultListableBeanFactory.registerBeanDefinition(className + "-clientProxy", beanDefinitionBuilder.getBeanDefinition());
}

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

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

public void setBaseUrl(URL baseUrl) {
this.baseUrl = baseUrl;
}

public void setScanPackage(String scanPackage) {
this.scanPackage = scanPackage;
}

public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

public void setContentType(String contextType) {
this.contentType = contextType;
}
}
package com.googlecode.jsonrpc4j.spring;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.googlecode.jsonrpc4j.JsonRpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
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 java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import static java.lang.String.format;
import static org.springframework.util.ClassUtils.convertClassNameToResourcePath;
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;

/**
* Auto-creates proxies for service interfaces annotated with {@link JsonRpcService}.
*/
@SuppressWarnings("unused")
public class AutoJsonRpcClientProxyCreator implements BeanFactoryPostProcessor, ApplicationContextAware, EnvironmentAware {

private static final Logger logger = LoggerFactory.getLogger(AutoJsonRpcClientProxyCreator.class);
private ApplicationContext applicationContext;
private Environment environment;
private String scanPackage;
private URL baseUrl;
private ObjectMapper objectMapper;
private String contentType;

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(applicationContext);
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
String resolvedPath = resolvePackageToScan();
logger.debug("Scanning '{}' for JSON-RPC service interfaces.", resolvedPath);
try {
for (Resource resource : applicationContext.getResources(resolvedPath)) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
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");
path = this.environment.resolvePlaceholders(path);
logger.debug("Found JSON-RPC service to proxy [{}] on path '{}'.", className, path);
registerJsonProxyBean(defaultListableBeanFactory, className, path);
}
}
}
} catch (IOException e) {
throw new IllegalStateException(format("Cannot scan package '%s' for classes.", resolvedPath), e);
}
}

/**
* Converts the scanPackage to something that the resource loader can handleRequest.
*/
private String resolvePackageToScan() {
return CLASSPATH_URL_PREFIX + convertClassNameToResourcePath(scanPackage) + "/**/*.class";
}

/**
* Registers a new proxy bean with the bean factory.
*/
private void registerJsonProxyBean(DefaultListableBeanFactory defaultListableBeanFactory, String className, String path) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(JsonProxyFactoryBean.class)
.addPropertyValue("serviceUrl", appendBasePath(path))
.addPropertyValue("serviceInterface", className);

if (objectMapper != null) {
beanDefinitionBuilder.addPropertyValue("objectMapper", objectMapper);
}

if (contentType != null) {
beanDefinitionBuilder.addPropertyValue("contentType", contentType);
}

defaultListableBeanFactory.registerBeanDefinition(className + "-clientProxy", beanDefinitionBuilder.getBeanDefinition());
}

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

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


@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}

public void setBaseUrl(URL baseUrl) {
this.baseUrl = baseUrl;
}

public void setScanPackage(String scanPackage) {
this.scanPackage = scanPackage;
}

public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

public void setContentType(String contextType) {
this.contentType = contextType;
}
}

0 comments on commit 5abebf3

Please sign in to comment.