#RestController cannot convert from ResponseEntity<Void> - spring

I've got following code for my REST Controller:
#RequestMapping(value = "foo", method = RequestMethod.GET)
public ResponseEntity<Result> doSomething(#RequestParam int someParam)
{
try
{
final Result result = service.getByParam(someParam);
if (result == null)
{
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else
{
return ResponseEntity.ok(result);
}
} catch (Exception ex)
{
LOG.error("Error blah", ex);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I would like to use ResponseEntity.noContent().build() but Eclipse gives me:
Type mismatch: cannot convert from ResponseEntity to
ResponseEntity
Is there any way to overcome this?
Update:
It is possible to create helper like this:
public class ResponseUtils
{
public static <T> ResponseEntity<T> noContent()
{
return withStatus(HttpStatus.NO_CONTENT);
}
public static <T> ResponseEntity<T> internalServerError()
{
return withStatus(HttpStatus.INTERNAL_SERVER_ERROR);
}
public static <T> ResponseEntity<T> accepted()
{
return withStatus(HttpStatus.ACCEPTED);
}
private static <T> ResponseEntity<T> withStatus(HttpStatus status)
{
return new ResponseEntity<T>(status);
}
}
So I can use it like:
return ResponseUtils.noContent();
But maybe there is built-in functionality for this stuff?

Is this that you want to achieve?
#RequestMapping(value = "foo", method = RequestMethod.GET)
public ResponseEntity<Result> doSomething(#RequestParam int someParam) {
try {
final Result result = service.getByParam(someParam);
if (result == null) {
return ResponseUtils.noContent();
} else {
return new ResponseEntity<Result>(result, null, HttpStatus.ACCEPTED);
}
} catch (Exception ex) {
return ResponseUtils.internalServerError();
}
}
//you forgot to add static keyword in this Utils class
public static class ResponseUtils{
public static <T> ResponseEntity<T> noContent(){
return withStatus(HttpStatus.NO_CONTENT);
}
public static <T> ResponseEntity<T> internalServerError(){
return withStatus(HttpStatus.INTERNAL_SERVER_ERROR);
}
public static <T> ResponseEntity<T> accepted(){
return withStatus(HttpStatus.ACCEPTED);
}
private static <T> ResponseEntity<T> withStatus(HttpStatus status){
return new ResponseEntity<T>(status);
}
}
Check imports, I am using:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.xml.transform.Result;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

Related

How can I test a my rest controller that has feign clients?

I have a rest controller that is using 2 fein clients, I want to write and test the Rest controller with different samples, I am not an expert at writing springboot tests.
In this scenario I have no repositories to test with, just feign clients accessed through a rest controller. Below is my testing controller code
#RestController
public class CustomerController {
#Autowired
private CustomerClient customerClient;
#Autowired
private PaymentsClient paymentsClient;
#RequestMapping(path = "/getAllCustomers", method = RequestMethod.GET)
public ResponseEntity<Object> getAllCustomers() {
List<Customer> customers = customerClient.getAllCustomers();
return new ResponseEntity<>(customers, HttpStatus.OK);
}
#RequestMapping(path = "/{customerId}", method = RequestMethod.GET)
public ResponseEntity<Object> get(#PathVariable() long customerId) {
try {
Customer c = customerClient.getCustomerById(customerId);
if (c != null) {
return new ResponseEntity<>(c, HttpStatus.OK);
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Customer Not Found");
}
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
#RequestMapping(path = "/{customerId}", method = RequestMethod.PATCH)
public ResponseEntity<Object> UpdateCustomer(#PathVariable() Long customerId, #RequestBody Customer customer) {
Customer c;
try {
c = customerClient.update(customerId, customer);
if (c != null) {
return new ResponseEntity<>(c, HttpStatus.OK);
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Customer Not Found");
}
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
#RequestMapping(path = "", method = RequestMethod.POST)
public ResponseEntity<Object> saveCustomer(#RequestBody Customer customer) {
Customer c;
try {
c = customerClient.saveCustomer(customer);
return new ResponseEntity<>(c, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
#RequestMapping(path = "/registerPayment", method = RequestMethod.POST)
public ResponseEntity<Object> saveCustomer(#RequestBody Payment payment) {
Payment p = null;
Customer c = null;
try {
c = customerClient.getCustomerById(payment.getCustomerId());
p = paymentsClient.saveCustomer(payment);
return new ResponseEntity<>(p, HttpStatus.OK);
} catch (Exception e) {
if (null == c) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body("Customer Does not Exist");
} else {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
}
Most of the tests I have seen have a repository injected in but for my case
I dont have those, just fein clients, Im I doing it wrong,
Below is my current test
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
public class CustomerControllerTest {
#Autowired
private MockMvc mockMvc;
#InjectMocks
private CustomerController customerController;
#Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(customerController).build();
}
#Test
public void getAllCustomers() {
try {
this.mockMvc.perform(get("/getAllCustomers")).andExpect(status().isOk())
.andExpect(content().json("[{\n" + " \"customerId\": 24,\n"
+ " \"firstName\": \"Benjamin\",\n" + " \"secondName\": \" Masiga\",\n"
+ " \"email\": \"ben#ben.com\"\n" + " }"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I'm getting the error below,
NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc' available: expected at least 1 bean which qualifies as autowire candidate.
Its as simple as writing any other JUnit test.
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
public class CustomerControllerTest {
#Mock
private CustomerClient customerClient;
#InjectMocks
private CustomerController customerController;
#Test
public void getAllCustomers() {
List<Customer> customers = new ArrayList<>();
customers.add(new Customers("name"));
Mockito.when(customerClient.getAllCustomers()).thenReturn(customers);
Mockito.assertEquals(customers.toString(),customerController.getAllCustomers())
}
}
You need your own feign.Client that works beyond MockMvc:
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.function.Function.identity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
import feign.Client;
import feign.Request;
import feign.Response;
import java.io.UncheckedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
public class MockMvcFeignClient implements Client {
private final MockMvc mockMvc;
public MockMvcFeignClient(MockMvc mockMvc) {
this.mockMvc = mockMvc;
}
#Override
public Response execute(Request request, Request.Options options) {
URI requestUrl = URI.create(request.url());
List<String> uriVars = new ArrayList<>();
String urlTemplate = fillVarsAndGetUrlTemplate(requestUrl, uriVars);
HttpMethod method = HttpMethod.valueOf(request.method());
byte[] body = request.body();
HttpHeaders httpHeaders = convertHeaders(request);
MockHttpServletRequestBuilder requestBuilder = request(method, urlTemplate, uriVars.toArray())
.headers(httpHeaders)
.content(body);
MockHttpServletResponse resp;
try {
ResultActions resultActions = mockMvc.perform(requestBuilder);
resp = resultActions.andReturn()
.getResponse();
} catch (Exception e) {
throw new IllegalStateException("Error while executing request", e);
}
return convertResponse(request, resp);
}
static String fillVarsAndGetUrlTemplate(URI requestUrl, List<String> uriVars) {
StringBuilder urlTemplate = new StringBuilder(requestUrl.getPath());
if (requestUrl.getQuery() != null) {
urlTemplate.append('?');
String[] pairs = requestUrl.getRawQuery().split("&");
for (int i = 0; i < pairs.length; i++) {
String pair = pairs[i];
int separator = pair.indexOf('=');
String paramName;
String paramValue;
if (separator < 0) {
paramName = pair;
paramValue = null;
} else {
paramName = pair.substring(0, separator);
try {
paramValue = URLDecoder.decode(pair.substring(separator + 1), UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new UncheckedIOException(e);
}
}
urlTemplate.append(i == 0 ? paramName : "&" + paramName);
if (paramValue != null) {
urlTemplate.append("={").append(paramName).append('}');
uriVars.add(paramValue);
}
}
}
return urlTemplate.toString();
}
private static HttpHeaders convertHeaders(Request request) {
HttpHeaders headers = new HttpHeaders();
request.headers().forEach((header, values) -> headers.put(header, new ArrayList<>(values)));
return headers;
}
private static Response convertResponse(Request request, MockHttpServletResponse resp) {
return Response.builder()
.request(request)
.status(resp.getStatus())
.body(resp.getContentAsByteArray())
.headers(resp.getHeaderNames().stream()
.collect(Collectors.toMap(identity(), resp::getHeaders)))
.build();
}
}
and create your feign client with it:
return Feign.builder()
.client(new MockMvcFeignClient(mockMvc))
...
So for tests where you could make MockMvc integration tests, now you can call it via feign client.

Webflux doesn't support ResponseBodyAdvice yet?

Since ResponseBodyAdvice interface is in web.servlet package
How could I implement such functions in webflux?
I also have this problem, i found it can be done by HandlerResultHandler.
For Example, I extend ResponseBodyResultHandler to wrap all my response
First, you should write ResponseWrapper.java
public class ResponseWrapper extends ResponseBodyResultHandler {
private static MethodParameter param;
static {
try {
//get new params
param = new MethodParameter(ResponseWrapper.class
.getDeclaredMethod("methodForParams"), -1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public ResponseWrapper(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver) {
super(writers, resolver);
}
private static Mono<Response> methodForParams() {
return null;
}
#Override
public boolean supports(HandlerResult result) {
boolean isMono = result.getReturnType().resolve() == Mono.class;
boolean isAlreadyResponse = result.getReturnType().resolveGeneric(0) == Response.class;
return isMono && !isAlreadyResponse;
}
#Override
#SuppressWarnings("unchecked")
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Preconditions.checkNotNull(result.getReturnValue(), "response is null!");
// modify the result as you want
Mono<Response> body = ((Mono<Object>) result.getReturnValue()).map(Response::success)
.defaultIfEmpty(Response.success());
return writeBody(body, param, exchange);
}
}
Then, add Bean in SpringBootApplication
#SpringBootApplication
public class SmartApplication {
#Autowired
ServerCodecConfigurer serverCodecConfigurer;
#Autowired
RequestedContentTypeResolver requestedContentTypeResolver;
#Bean
ResponseWrapper responseWrapper() {
return new ResponseWrapper(serverCodecConfigurer
.getWriters(), requestedContentTypeResolver);
}
//Spring start
public static void main(String[] args) {
SpringApplication.run(SmartApplication.class, args);
}
}
My response class, for reference
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Response<T> {
boolean success;
T data;
Object error;
String warning;
public Response() {
}
public static Response success() {
return success(null);
}
public static <T> Response success(T data) {
return new Response<T>().setSuccess(true).setData(data);
}
public static Response error(Throwable e) {
LogManager.getLogger(StackLocatorUtil.getCallerClass(2)).info(e);
return new Response().setSuccess(false).setError(e);
}
public static Response error(Object e) {
return new Response().setSuccess(false).setError(e);
}
public static Response error(String e) {
return new Response().setSuccess(false).setError(e);
}
/* get success */
public boolean isSuccess() {
return success;
}
/* set success */
public Response setSuccess(boolean success) {
this.success = success;
return this;
}
/* get data */
public Object getData() {
return data;
}
/* set data */
public Response setData(T data) {
this.data = data;
return this;
}
/* get error */
public Object getError() {
return error;
}
/* set error */
public Response setError(Object error) {
this.error = error;
return this;
}
}
i used ResponseBodyAdvise before spring 5.0. i think ResponseBodyResultHandler suport webflux since spring5.0.

Spring equivalent for CDI Instance

I am new to Spring and i need to convert a CDI class to Spring.
I have the below code in CDI
#Inject
private Instance<HealthCheck> healthChecks;
I then iterate over healthChecks.
I found a similar question What is the Spring equivalent for CDI's Instance, or Guices Provider , where it was advised to use
#Inject
Provider<MyObject> myObjectInstance;
//...
MyObject myObjectInstance.get();
However, since provider does not implements iterable, I am not able to iterate.
Can someone please help me on how can I convert the CDI code block to spring.
create a new file spring.factories inside META-INF with following content:
org.springframework.context.ApplicationContextInitializer=package_name.CustomApplicationContextInitializer
or you can use it in your junit test like:
#SpringApplicationConfiguration(initializers = CustomApplicationContextInitializer.class)
And now you can use like:
#Autowired
private Instance<HealthCheck> healthChecks;
CustomApplicationContextInitializer.class
public class CustomApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Configure custom CustomAutowireCandidateResolver to handle CDI
// Instance<T> dependency requests
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
beanFactory.setAutowireCandidateResolver(new CustomAutowireCandidateResolver());
}
}
CustomAutowireCandidateResolver.class
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Priority;
import javax.enterprise.inject.Instance;
import javax.enterprise.util.TypeLiteral;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
public class CustomAutowireCandidateResolver extends ContextAnnotationAutowireCandidateResolver {
static final boolean IS_CDI_INSTANCE_CLASS_PRESENT = ClassUtils.isPresent("javax.enterprise.inject.Instance", null);
#Override
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
if (IS_CDI_INSTANCE_CLASS_PRESENT && Instance.class.equals(descriptor.getDependencyType())) {
// TODO refactor getLazyResolutionProxyIfNecessary to allow to
// customize lazy dependency resolution for Instance<T>
return getInstanceAdapterFor(descriptor);
}
return super.getLazyResolutionProxyIfNecessary(descriptor, beanName);
}
#SuppressWarnings({ "unchecked", "rawtypes" })
private Object getInstanceAdapterFor(DependencyDescriptor descriptor) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) getBeanFactory();
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) listableBeanFactory;
// Instance<TargetType>
Class targetType = descriptor.getResolvableType().getGeneric(0).getRawClass();
Map<String, Object> beansOfType = listableBeanFactory.getBeansOfType(targetType);
List<Bean> beansInstances = beansOfType.entrySet().stream() //
.map(e -> new Bean(e.getValue(), registry.getBeanDefinition(e.getKey()).isPrimary()))//
.collect(Collectors.toList());
Annotation[] qualifiers = retainQualifierAnnotations(descriptor.getAnnotations());
Beans beans = new Beans(targetType, beansInstances);
return qualifiers.length == 0 ? beans : beans.select(qualifiers);
}
private Annotation[] retainQualifierAnnotations(Annotation[] annotations) {
return Arrays.stream(annotations) //
.filter(a -> a.annotationType().isAnnotationPresent(Qualifier.class)) //
.toArray(Annotation[]::new);
}
static class Beans<T> implements Instance<T> {
private final List<Bean> beans;
private final Class<?> type;
public Beans(Class<?> type, List<Bean> beans) {
this.type = type;
this.beans = beans;
}
protected List<Bean> getBeans() {
return beans;
}
#Override
public T get() {
return (T) findDefaultInstance();
}
protected Object findDefaultInstance() {
List<Bean> beans = getBeans();
if (beans.size() == 1) {
return beans.get(0).getInstance();
}
Object highestPrioBean = returnPrimaryOrHighestPriorityBean(beans);
if (highestPrioBean != null) {
return highestPrioBean;
}
// TODO figure out a sane default to use here - maybe throw an
// exception?
return beans.get(0).getInstance();
}
private Object returnPrimaryOrHighestPriorityBean(List<Bean> beans) {
long highestPriority = Integer.MIN_VALUE;
Object highestPrioBean = null;
for (Bean bean : beans) {
if (bean.isPrimary()) {
return bean.getInstance();
}
// TODO figure out to retrieve order from BeanDefinition /
// BeanDeclaration
Object instance = bean.getInstance();
Order order = instance.getClass().getAnnotation(Order.class);
if (order != null) {
if (order.value() > highestPriority) {
highestPriority = order.value();
highestPrioBean = instance;
}
}
Priority priority = instance.getClass().getAnnotation(Priority.class);
if (priority != null) {
if (priority.value() > highestPriority) {
highestPriority = priority.value();
highestPrioBean = instance;
}
}
}
return highestPrioBean;
}
#Override
#SuppressWarnings("unchecked")
public Instance<T> select(Annotation... qualifiers) {
return select((Class<T>) type, qualifiers);
}
#Override
public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers) {
return new Beans<U>(subtype, filterBeans(subtype, qualifiers));
}
protected List<Bean> filterBeans(Class<?> subtype, Annotation... qualifiers) {
List<Annotation> requiredQualifiers = Arrays.asList(qualifiers);
return getBeans().stream() //
.filter(bean -> subtype.isInstance(bean.getInstance())) //
.filter(bean -> bean.getAnnotations().containsAll(requiredQualifiers)) //
.collect(Collectors.toList());
}
#Override
public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
// TODO implement (Class<U> subtype, Annotation... qualifiers) via
// select(TypeLiteral<U> subtype, Annotation... qualifiers)
return select(subtype.getRawType(), qualifiers);
}
#Override
public Iterator<T> iterator() {
return getBeans().stream().map(bean -> (T) bean.getInstance()).iterator();
}
#Override
public boolean isUnsatisfied() {
return getBeans().isEmpty();
}
#Override
public boolean isAmbiguous() {
return getBeans().size() > 1;
}
#Override
public void destroy(Object bean) {
if (bean instanceof DisposableBean) {
try {
((DisposableBean) bean).destroy();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
static class Bean {
private final boolean primary;
private final Object instance;
private final List<Annotation> annotations;
public Bean(Object instance, boolean primary) {
this.primary = primary;
this.instance = instance;
this.annotations = Arrays.asList(instance.getClass().getAnnotations());
}
public Object getInstance() {
return instance;
}
public boolean isPrimary() {
return primary;
}
public List<Annotation> getAnnotations() {
return annotations;
}
}
}
here is full source link: https://github.com/thomasdarimont/spring-boot-cdi-instance-example

What is the best way to use #ConfigurationProperties with Builders?

I have searched and can't find any examples that would show me a better way to do this, but in the Spring/Spring Boot code, there are generic builders but the builder itself seems to apply the properties programmatically. Here is some code trying to configure 2 Oracle Connection Pool Data Sources:
import oracle.ucp.jdbc.PoolDataSourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.sql.SQLException;
#Configuration
#EnableConfigurationProperties
#ConditionalOnClass(PoolDataSourceFactory.class)
public class PersistenceAutoConfiguration {
#Bean (name = "readWriteDataSource")
public DataSource getReadWriteDataSource() throws SQLException {
OracleUcpDataSourceProperties rwProperties = getReadWriteProperties();
return OracleUcpDataSourceBuilder.create()
.connectionFactoryClassName(rwProperties.getConnectionFactoryClassName())
.url(rwProperties.getUrl())
.user(rwProperties.getUser())
.password(rwProperties.getPassword())
.initialPoolSize(rwProperties.getInitialPoolSize())
.minPoolSize(rwProperties.getMinPoolSize())
.maxPoolSize(rwProperties.getMaxPoolSize())
.connectionWaitTimeout(rwProperties.getConnectionWaitTimeout())
.inactiveConnectionTimeout(rwProperties.getInactiveConnectionTimeout())
.maxIdleTime(rwProperties.getMaxIdleTime())
.build();
}
#Bean (name = "readOnlyDataSource")
public DataSource getReadOnlyDataSource() throws SQLException {
OracleUcpDataSourceProperties roProperties = getReadOnlyProperties();
return OracleUcpDataSourceBuilder.create()
.connectionFactoryClassName(roProperties.getConnectionFactoryClassName())
.url(roProperties.getUrl())
.user(roProperties.getUser())
.password(roProperties.getPassword())
.initialPoolSize(roProperties.getInitialPoolSize())
.minPoolSize(roProperties.getMinPoolSize())
.maxPoolSize(roProperties.getMaxPoolSize())
.connectionWaitTimeout(roProperties.getConnectionWaitTimeout())
.inactiveConnectionTimeout(roProperties.getInactiveConnectionTimeout())
.maxIdleTime(roProperties.getMaxIdleTime())
.build();
}
#ConfigurationProperties(prefix = "datasource.readwrite")
#Bean(name = "readWriteProperties")
protected OracleUcpDataSourceProperties getReadWriteProperties() {
return new OracleUcpDataSourceProperties();
}
#ConfigurationProperties(prefix = "datasource.readonly")
#Bean(name = "readOnlyProperties")
protected OracleUcpDataSourceProperties getReadOnlyProperties() {
return new OracleUcpDataSourceProperties();
}
}
and
public class OracleUcpDataSourceProperties {
private String connectionFactoryClassName;
private String url;
private String user;
private String password;
private int initialPoolSize;
private int minPoolSize;
private int maxPoolSize;
private int connectionWaitTimeout;
private int inactiveConnectionTimeout;
private int maxIdleTime;
private Boolean validateConnectionOnBorrow;
public String getConnectionFactoryClassName() {
return connectionFactoryClassName;
}
public void setConnectionFactoryClassName(String connectionFactoryClassName) {
this.connectionFactoryClassName = connectionFactoryClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getInitialPoolSize() {
return initialPoolSize;
}
public void setInitialPoolSize(int initialPoolSize) {
this.initialPoolSize = initialPoolSize;
}
public int getMinPoolSize() {
return minPoolSize;
}
public void setMinPoolSize(int minPoolSize) {
this.minPoolSize = minPoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getConnectionWaitTimeout() {
return connectionWaitTimeout;
}
public void setConnectionWaitTimeout(int connectionWaitTimeout) {
this.connectionWaitTimeout = connectionWaitTimeout;
}
public int getInactiveConnectionTimeout() {
return inactiveConnectionTimeout;
}
public void setInactiveConnectionTimeout(int inactiveConnectionTimeout) {
this.inactiveConnectionTimeout = inactiveConnectionTimeout;
}
public int getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(int maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
public Boolean getValidateConnectionOnBorrow() {
return validateConnectionOnBorrow;
}
public void setValidateConnectionOnBorrow(Boolean validateConnectionOnBorrow) {
this.validateConnectionOnBorrow = validateConnectionOnBorrow;
}
}
and
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import java.sql.SQLException;
public class OracleUcpDataSourceBuilder {
private PoolDataSource pds;
/**
* This will grab the pool factory and initialize it.
*/
public OracleUcpDataSourceBuilder() throws SQLException {
pds = PoolDataSourceFactory.getPoolDataSource();
}
public static OracleUcpDataSourceBuilder create() throws SQLException {
return new OracleUcpDataSourceBuilder();
}
public OracleUcpDataSourceBuilder connectionFactoryClassName(String connectionFactoryClassName) throws SQLException {
pds.setConnectionFactoryClassName(connectionFactoryClassName);
return this;
}
public OracleUcpDataSourceBuilder url(String url) throws SQLException {
pds.setURL(url);
return this;
}
public OracleUcpDataSourceBuilder user(String user) throws SQLException {
pds.setUser(user);
return this;
}
public OracleUcpDataSourceBuilder password(String password) throws SQLException {
pds.setPassword(password);
return this;
}
public OracleUcpDataSourceBuilder initialPoolSize(int initialPoolSize) throws SQLException {
pds.setInitialPoolSize(initialPoolSize);
return this;
}
public OracleUcpDataSourceBuilder minPoolSize(int minPoolSize) throws SQLException {
pds.setMinPoolSize(minPoolSize);
return this;
}
public OracleUcpDataSourceBuilder maxPoolSize(int maxPoolSize) throws SQLException {
pds.setMaxPoolSize(maxPoolSize);
return this;
}
public OracleUcpDataSourceBuilder connectionWaitTimeout(int connectionWaitTimeout) throws SQLException {
pds.setConnectionWaitTimeout(connectionWaitTimeout);
return this;
}
public OracleUcpDataSourceBuilder inactiveConnectionTimeout(int inactiveConnectionTime) throws SQLException {
pds.setInactiveConnectionTimeout(inactiveConnectionTime);
return this;
}
public OracleUcpDataSourceBuilder maxIdleTime(int maxIdleTime) throws SQLException {
pds.setMaxIdleTime(maxIdleTime);
return this;
}
public PoolDataSource build() {
return pds;
}
}
Preferably, I would like to be able to apply the properties directly to the builder in one place. is this possible? what changes would I have to make?
Thanks...
Here is your builder, sir
public class OracleUcpDataSourceBuilder {
private Map<String, String> properties = new HashMap<String, String>();
private static final String[] REQ_PROPERTIES = new String[] {"username", "password", "URL"};
public static OracleUcpDataSourceBuilder create() {
return new OracleUcpDataSourceBuilder();
}
public DataSource build() {
for (String prop : REQ_PROPERTIES) {
Assert.notNull(properties.get(prop), "Property is required:" + prop);
}
PoolDataSource result = PoolDataSourceFactory.getPoolDataSource();
bind(result);
return result;
}
private void bind(DataSource result) {
MutablePropertyValues properties = new MutablePropertyValues(this.properties);
new RelaxedDataBinder(result).bind(properties);
}
public OracleUcpDataSourceBuilder URL(String url) {
this.properties.put("URL", url);
return this;
}
public OracleUcpDataSourceBuilder username(String username) {
this.properties.put("username", username);
return this;
}
public OracleUcpDataSourceBuilder password(String password) {
this.properties.put("password", password);
return this;
}
}
Just define a bean like this:
#Bean (name = "readOnlyDataSource")
#ConfigurationProperties(prefix = "datasource.readonly")
public DataSource getReadOnlyDataSource() {
return OracleUcpDataSourceBuilder.create().build();
}
Just make sure that the property names are correct. Spring will take care of the rest.
Note: I use DataSourceBuilder or Spring as a reference.. You can check it's source code also.
Edit: Added some methods to make sure some properties are configured. But this way, you need to set those properties manually to make sure that they're available.

Spring/JSF2 and #ViewScoped

I want to use spring managed beans for my JSF2 controllers so that autowiring works. I know that there is no #ViewScoped in spring and I know a few implementations of #ViewScoped floating around various blogs (one from the primefaces lead).
Is any of them used in a real application and considered stable? Maybe one of them is recommended or widely used and I'm just not able to find it.
There is one :) Without memory leaks and with #PreDestroy support. Tested in production. Here.
package org.nkey.primefaces.scopes.test.spring.scope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PreDestroyViewMapEvent;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* #author m.nikolaev Date: 21.11.12 Time: 0:37
*/
public class ViewScope implements Scope, Serializable, HttpSessionBindingListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ViewScope.class);
private final WeakHashMap<HttpSession, Set<ViewScopeViewMapListener>> sessionToListeners = new WeakHashMap<>();
#Override
public Object get(String name, ObjectFactory objectFactory) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (viewMap) {
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
LOGGER.debug("Creating bean {}", name);
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
}
#Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
#Override
public String getConversationId() {
return null;
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
LOGGER.debug("registerDestructionCallback for bean {}", name);
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
ViewScopeViewMapListener listener =
new ViewScopeViewMapListener(viewRoot, name, callback, this);
viewRoot.subscribeToViewEvent(PreDestroyViewMapEvent.class, listener);
HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
final Set<ViewScopeViewMapListener> sessionListeners;
synchronized (sessionToListeners) {
if (!sessionToListeners.containsKey(httpSession)) {
sessionToListeners.put(httpSession, new HashSet<ViewScopeViewMapListener>());
}
sessionListeners = sessionToListeners.get(httpSession);
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionListeners) {
Set<ViewScopeViewMapListener> toRemove = new HashSet<>();
for (ViewScopeViewMapListener viewMapListener : sessionListeners) {
if (viewMapListener.checkRoot()) {
toRemove.add(viewMapListener);
}
}
sessionListeners.removeAll(toRemove);
sessionListeners.add(listener);
}
if (!FacesContext.getCurrentInstance().getExternalContext().getSessionMap().containsKey("sessionBindingListener")) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionBindingListener", this);
}
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
#Override
public void valueBound(HttpSessionBindingEvent event) {
LOGGER.debug("Session event bound {}", event.getName());
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
LOGGER.debug("Session event unbound {}", event.getName());
final Set<ViewScopeViewMapListener> listeners;
synchronized (sessionToListeners) {
if (sessionToListeners.containsKey(event.getSession())) {
listeners = sessionToListeners.get(event.getSession());
sessionToListeners.remove(event.getSession());
} else {
listeners = null;
}
}
if (listeners != null) {
for (ViewScopeViewMapListener listener : listeners) {
listener.doCallback();
}
}
}
public void clearFromListener(ViewScopeViewMapListener listener) {
LOGGER.debug("Removing listener from map");
HttpSession httpSession = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (httpSession != null) {
synchronized (sessionToListeners) {
if (sessionToListeners.containsKey(httpSession)) {
sessionToListeners.get(httpSession).remove(listener);
}
}
}
}
}

Resources