I'm using spring-data-couchbase:2.0.0.RC1 in my app but I have some legacy code that relies on Bucket object and work with it directly. Is there a way how to get Bucket object from spring-data-couchbase ? I found this http://docs.spring.io/spring-data/couchbase/docs/2.0.0.RC1/reference/html/#couchbase.template in documentation but can't figure out, how to configure it in my app.
My spring config object is as below ...
#Configuration
public class SpringCouchbaseConfig extends AbstractCouchbaseConfiguration {
#Value("${scheduled.task.couchbase_sync.host}")
String host;
#Value("${scheduled.task.couchbase_sync.bucket}")
String bucket;
#Override
protected List<String> getBootstrapHosts() {
return Arrays.asList(this.host);
}
#Override
protected String getBucketName() {
return this.bucket;
}
#Override
protected String getBucketPassword() {
return "";
}
#Override
protected CouchbaseEnvironment getEnvironment() {
return DefaultCouchbaseEnvironment.builder()
.connectTimeout(TimeUnit.SECONDS.toMillis(10))
.computationPoolSize(6)
.build();
}
#Bean(name = "org.springframework.data.couchbase.core.convert.customConversions")
public CustomConversions customConversions() {
return new CustomConversions(Collections.emptyList());
}
}
If you are only configuring one Bucket, the AbstractCouchbaseConfiguration will declare a #Bean named couchbaseBucket of type Bucket so you could autowire it where you need it:
#Autowired
private Bucket myBucketUsedBySpringData;
If you have a reference to the CouchbaseTemplate (eg. also autowired somewhere) you can also easily obtain the backing Bucket by calling getCouchbaseBucket() on it.
Related
I created a class using ResourceBundle interface as shown below. This class is dependent on another class. The implementation class for ResourceBundle (QuestionnaireSource as shown below) always has null as dependencies. No matter if I use setter or constructor injection.
Could someone please help me with this issue. I am I missing some configuration here.
#Component
public class QuestionnaireSource extends ResourceBundle {
private final QuestionnaireCache questionnaireCache;
private static final Object lockObject = new Object();
#Override
protected Object handleGetObject(String key) {
// Gets an object for the given key from this resource bundle.
// Returns null if this resource bundle does not contain an object for the given key 0
Object value = null;
try {
value = getString(key, LocaleContextHolder.getLocale());
} catch (Exception ignored) {
}
return value;
}
public Questionnaire getString(String key, Locale locale) {
Locale l = safeLocale(locale);
return getResources(l).get(key);
}
private Locale safeLocale(Locale l) {
if (l.getLanguage().equalsIgnoreCase("DE")) {
return Locale.GERMAN;
} else {
return Locale.ENGLISH;
}
}
protected Map<String, Questionnaire> getResources(Locale locale) {
synchronized (lockObject) {
return questionnaireCache.getQuestionnaireCache().get(locale.getLanguage().toUpperCase());
}
}
#Override
public Enumeration<String> getKeys() {
return null;
}
public QuestionnaireSource(QuestionnaireCache questionnaireCache) {
super();
this.questionnaireCache = questionnaireCache;
}
}
Update:
I found that even simple dependency injection in resourceBundle is failing.
UPdate2:
The way I am using in the main class is as follows:
// ResourceBundle test here
System.out.println("Test here for resource bundle");
Locale locale = new Locale("de", "DE");
ResourceBundle bundle = ResourceBundle.getBundle("com.app.util.QuestionnaireSource", locale);
System.out.println(bundle.getString("some.test.string"));
Update3
I am writing a simple example to convey the scenario:
Some service class
#Service
public class SomeServiceTest {
public String testMethod(){
return "test here and complete";
}
}
Some example implementation of resource bundle
#Component
public class MyResourceBundle extends ResourceBundle {
private final SomeServiceTest someServiceTest;
#Autowired
public MyResourceBundle(SomeServiceTest someServiceTest) {
this.someServiceTest = someServiceTest;
}
#Override
protected Object handleGetObject(String key) {
if(key.equals("test"))
return "test";
return null;
}
#Override
public Enumeration<String> getKeys() {
return null;
}
}
Main.java
main(){
// ResourceBundle test here
System.out.println("Test here for resource bundle");
Locale locale = new Locale("de", "DE");
ResourceBundle bundle = ResourceBundle.getBundle("com.app.util.MyResourceBundle", locale);
System.out.println(bundle.getString("test"));
}
Update4:
I changed the annotation on classes as mentioned by on this post https://www.baeldung.com/spring-inject-bean-into-unmanaged-objects
but still I have the null dependency injection for SomeServiceTest class. The changes are as shown below.
SomeServiceTest.java
#Service
public class SomeServiceTest {
public String testMethod(){
return "test here and complete";
}
}
MyResourceBundle.java
#Configurable
public class MyResourceBundle extends ResourceBundle {
#Autowired
private SomeServiceTest someServiceTest;
public MyResourceBundle() {
}
#Override
protected Object handleGetObject(String key) {
if(key.equals("test"))
return someServiceTest.testMethod();
return null;
}
#Override
public Enumeration<String> getKeys() {
return null;
}
}
still SomeServiceTest class is null.
Can you please post an example on how you are using this class? Is it you (your code) or spring who instanciate it (on startup)?
#Component only works for beans which Spring instanciate. If you want to inject stuff in classes you instanciate in you code you can annotate the class with #Configurable.
Please see https://www.baeldung.com/spring-inject-bean-into-unmanaged-objects for some examples.
Make sure you have initialized the spring context
If you are using spring boot
You can get the application context after it starts and use it to get the bean you want
For example
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(YouApplication.class, args);
MyResourceBundle resConfig = run.getBean("myResourceBundle", MyResourceBundle .class);
resConfig.handleGetObject("test");
}
Unfortunately ResourceBundle.getBundle does not initialize the spring application context
How can I connect redis and couchbase to my spring application.
I get this error Parameter 0 of method couchbaseMappingContext in org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration required a single bean, but 2 were found: - couchbaseCustomConversions: defined by method 'customConversions' in class path resource [{classPath}/chat/config/CouchbaseConfiguration.class] - redisCustomConversions: defined in null
I only need redis to 'look' at one package and the other ones need to be connected with only couchbase.
Redis config
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
#Bean
public RedisTemplate<Long, ?> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Long, ?> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// Add some specific configuration here. Key serializers, etc.
return template;
}
Couchbase config
#EnableCouchbaseRepositories
#Configuration
public class CouchbaseConfiguration extends AbstractCouchbaseConfiguration {
#Value("${spring.data.couchbase.bucket-name}")
private String bucketName;
#Value("${spring.couchbase.username}")
private String username;
#Value("${spring.couchbase.password}")
private String password;
#Value("${spring.couchbase.connection-string}")
private String connectionString;
#Override
public String getConnectionString() {
return this.connectionString;
}
#Override
public String getUserName() {
return this.username;
}
#Override
public String getPassword() {
return this.password;
}
#Override
public String getBucketName() {
return this.bucketName;
}
}
and when I first start my app in terminal there is this info : Spring Data Redis - Could not safely identify store assignment for repository candidate interface
To resolve the ambiguity in taking the customConversions bean, we could tell the couchbase configuration class how to create the customConversions bean. Adding the below code to the class which extends AbstractCouchbaseConfiguration should solve the issue
#Bean
public CustomConversions customConversions() {
return super.customConversions();
}
I would like to retrieve the value of a property in file application.properties in my service layer of my application, the value of setVersion is null
version=5.4.3
and the function for recovery the version
#Override
public ProductDto getVersionApp() {
ProductDto dto = new ProductDto();
Properties prop = new Properties();
try {
prop.load(new FileInputStream("/concerto-rest-api/src/main/resources/application.properties"));
dto.setVersion(prop.getProperty("version"));
LOG.info("version ",prop.getProperty("version"));
} catch (IOException ex) {}
return dto;
}
You can use #Value("${version}") in you service, provided you service is a spring bean.
If you are using the spring-boot framework, there are several ways you can get that property.
First:
#SpringBootApplication
public class SpringBoot01Application {
public static void main(String[] args) {
ConfigurableApplicationContext context=SpringApplication.run(SpringBoot01Application.class, args);
String str1=context.getEnvironment().getProperty("version");
System.out.println(str1);
}
}
Second:
#Component
public class Student {
#Autowired
private Environment env;
public void speak() {
System.out.println("=========>" + env.getProperty("version"));
}
}
Third:
#Component
#PropertySource("classpath:jdbc.properties")//if is application.properties,then you don't need to write #PropertyScource("application.properties")
public class Jdbc {
#Value("${jdbc.user}")
private String user;
#Value("${jdbc.password}")
private String password;
public void speack(){
System.out.println("username:"+user+"------"+"password:"+password);
}
}
I am caching data using spring cache. Now i want to encrypt few data before writing into cache and decrypt data while reading. So is there any way i can write custom interceptor/aop for #cachable annotation
Instead of using AOP you can simply use a decorator for your Cache and CacheResolver.
public class EncodingCacheResolver implements CacheResolver {
private final CacheResolver delegate;
public EncodingCacheResolver(CacheResolver delegate) {
this.delegate=delegate;
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
Collection<Cache> result = delegate.resolveCaches(context);
return result.stream().map(EncodingCache::new).collect(Collectors.toLlist());
}
}
The cache implementation
public class EncodingCache implements Cache {
private final Cache delegate;
public EncodingCache(Cache delegate) {
this.delegate=delegate;
}
public String getName() {
return delegate.getName();
}
public Object getNativeCache() {
return delegate.getNativeCache();
}
public void evict(Object key) {
delegate.evict(key)
}
public void put(Object key, Object value) {
Object encodedValue = encode(value);
this.delegate.put(key, encodedValue);
}
public <T> T get(Object key, Class<T> type) {
Object encodedValue = delegate.get(key, type);
return decode(encodedValue);
}
// Other Cache methods omitted but the pattern is the same
private Object encode(Object value) {
// encoding logic here
}
private Object decode(Object value) {
// decoding logic here
}
}
Then some configuration
#Configuration
#EnableCache
public void CacheConfiguration {
#Bean
public CacheResolver cacheResolver(CacheManager cacheManager) {
return new EncodingCacheResolver(SimpleCache.of(cacheManager));
}
}
Haven't tested the implementation, typed it from the top of my head. But this should more or less be what you need. You don't really need AOP for this.
In my Spring Boot application I'm using the #PreAuthorize annotation in my controller methods to make them authorized. The expressions use simple boolean-returning methods, like this:
#ResponseStatus(OK)
#PreAuthorize("#auth.authentication.mayReadMe(principal)")
public UserDto readMe() {
...
The mayReadMe(...) method simply returns a boolean value, however it uses ternary logic under the hood and just converts a special enum to boolean:
boolean mayReadMe(#Nonnull UserDetails principal);
Now let's say I want to rework the authorization components and let the method return the enum:
#Nonnull
foo.bar.FooBarEnum mayReadMe(#Nonnull final UserDetails principal);
However, I'm getting the following exception:
java.lang.IllegalArgumentException: Failed to evaluate expression '#primaryAuth.authentication.mayReadMe(principal)'
at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:15)
at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:44)
at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:57)
at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:25)
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
...
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E:(pos 0): Type conversion problem, cannot convert from #javax.annotation.Nonnull foo.bar.FooBarEnum to java.lang.Boolean
at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:78)
at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:53)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:301)
at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:11)
... 113 common frames omitted
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [#javax.annotation.Nonnull foo.bar.FooBarEnum] to type [java.lang.Boolean]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:74)
... 116 common frames omitted
The exception message is really clear, but I can't inject my custom converter in any way. What I've tried so far:
Registering custom converters via WebMvcConfigurerAdapter.addFormatters(FormatterRegistry) (both Converter and GenericConverter)
Bean-ining a custom ExpressionBasedPreInvocationAdvice (but it shouldn't work as far as I understand)
... and a few other ways I can't recall after spending a few hours unfortunately.
How do I inject a custom type converter so the #PreAuthorization expressions could be aware of the foo.bar.FooBarEnum as the returning type?
Edit 1
Why do I need a custom type to be returned, and not a boolean. I'm also writing a simple REST API self-describing subsystem, just a simple GET /api endpoint to return a list of endpoints and so on. This list consists of a certain objects describing API end point, HTTP method, incoming and outgoing DTOs, and the last thing I'm trying to add to the definition object is an endpoint authorization policy expression. Note that it's not a good idea to return the #PreAuthorize string expression (I mean a raw string), but it might be good to return a custom object describing the authorization rules. What I want the most is returning an object like:
public final class AuthorizationExpression
implements BooleanSupplier {
...
public IExpression toExpression() {
...
}
where BooleanSupplier is expected to be used in the converter I'm trying to inject in order to satisfy the authorization needs -- just return true or false, and where IExpression is expected to be toString-ed in the GET /api handler using the Spring expression evaluator. Hence the mayReadMe signature might be as follows:
AuthorizationExpression mayReadMe(...)
so I could use AuthorizationExpression up to a certain use case. The FooBarEnum is just a simplification for the original question prior to the edit.
A suggestion, let your enum implement the conversion method:
public enum FooBarEnum {
// previous code
public boolean booleanValue() {
// TODO
}
}
And change your annotation:
#PreAuthorize("#auth.authentication.mayReadMe(principal).booleanValue()")
Figured it out. I only need to tune the DefaultMethodSecurityExpressionHandler instance. Let's assume the net two classes as library ones:
public abstract class CustomTypesGlobalMethodSecurityConfiguration
extends GlobalMethodSecurityConfiguration {
protected abstract ApplicationContext applicationContext();
protected abstract ConversionService conversionService();
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
final ApplicationContext applicationContext = applicationContext();
final TypeConverter typeConverter = new StandardTypeConverter(conversionService());
final DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler() {
#Override
public StandardEvaluationContext createEvaluationContextInternal(final Authentication authentication, final MethodInvocation methodInvocation) {
final StandardEvaluationContext decoratedStandardEvaluationContext = super.createEvaluationContextInternal(authentication, methodInvocation);
return new ForwardingStandardEvaluationContext() {
#Override
protected StandardEvaluationContext standardEvaluationContext() {
return decoratedStandardEvaluationContext;
}
#Override
public TypeConverter getTypeConverter() {
return typeConverter;
}
};
}
};
handler.setApplicationContext(applicationContext);
return handler;
}
}
where ForwardingStandardEvaluationContext is a simple forwarding decorator to decorate an instance of StandardEvaluationContext because the latter is ConversionService-aware:
public abstract class ForwardingStandardEvaluationContext
extends StandardEvaluationContext {
protected abstract StandardEvaluationContext standardEvaluationContext();
#Override public void setRootObject(final Object rootObject, final TypeDescriptor typeDescriptor) { standardEvaluationContext().setRootObject(rootObject, typeDescriptor); }
#Override public void setRootObject(final Object rootObject) { standardEvaluationContext().setRootObject(rootObject); }
#Override public TypedValue getRootObject() { return standardEvaluationContext().getRootObject(); }
#Override public void addConstructorResolver(final ConstructorResolver resolver) { standardEvaluationContext().addConstructorResolver(resolver); }
#Override public boolean removeConstructorResolver(final ConstructorResolver resolver) { return standardEvaluationContext().removeConstructorResolver(resolver); }
#Override public void setConstructorResolvers(final List<ConstructorResolver> constructorResolvers) { standardEvaluationContext().setConstructorResolvers(constructorResolvers); }
#Override public List<ConstructorResolver> getConstructorResolvers() { return standardEvaluationContext().getConstructorResolvers(); }
#Override public void addMethodResolver(final MethodResolver resolver) { standardEvaluationContext().addMethodResolver(resolver); }
#Override public boolean removeMethodResolver(final MethodResolver methodResolver) { return standardEvaluationContext().removeMethodResolver(methodResolver); }
#Override public void setMethodResolvers(final List<MethodResolver> methodResolvers) { standardEvaluationContext().setMethodResolvers(methodResolvers); }
#Override public List<MethodResolver> getMethodResolvers() { return standardEvaluationContext().getMethodResolvers(); }
#Override public void setBeanResolver(final BeanResolver beanResolver) { standardEvaluationContext().setBeanResolver(beanResolver); }
#Override public BeanResolver getBeanResolver() { return standardEvaluationContext().getBeanResolver(); }
#Override public void addPropertyAccessor(final PropertyAccessor accessor) { standardEvaluationContext().addPropertyAccessor(accessor); }
#Override public boolean removePropertyAccessor(final PropertyAccessor accessor) { return standardEvaluationContext().removePropertyAccessor(accessor); }
#Override public void setPropertyAccessors(final List<PropertyAccessor> propertyAccessors) { standardEvaluationContext().setPropertyAccessors(propertyAccessors); }
#Override public List<PropertyAccessor> getPropertyAccessors() { return standardEvaluationContext().getPropertyAccessors(); }
#Override public void setTypeLocator(final TypeLocator typeLocator) { standardEvaluationContext().setTypeLocator(typeLocator); }
#Override public TypeLocator getTypeLocator() { return standardEvaluationContext().getTypeLocator(); }
#Override public void setTypeConverter(final TypeConverter typeConverter) { standardEvaluationContext().setTypeConverter(typeConverter); }
#Override public TypeConverter getTypeConverter() { return standardEvaluationContext().getTypeConverter(); }
#Override public void setTypeComparator(final TypeComparator typeComparator) { standardEvaluationContext().setTypeComparator(typeComparator); }
#Override public TypeComparator getTypeComparator() { return standardEvaluationContext().getTypeComparator(); }
#Override public void setOperatorOverloader(final OperatorOverloader operatorOverloader) { standardEvaluationContext().setOperatorOverloader(operatorOverloader); }
#Override public OperatorOverloader getOperatorOverloader() { return standardEvaluationContext().getOperatorOverloader(); }
#Override public void setVariable(final String name, final Object value) { standardEvaluationContext().setVariable(name, value); }
#Override public void setVariables(final Map<String, Object> variables) { standardEvaluationContext().setVariables(variables); }
#Override public void registerFunction(final String name, final Method method) { standardEvaluationContext().registerFunction(name, method); }
#Override public Object lookupVariable(final String name) { return standardEvaluationContext().lookupVariable(name); }
#Override public void registerMethodFilter(final Class<?> type, final MethodFilter filter) throws IllegalStateException { standardEvaluationContext().registerMethodFilter(type, filter); }
}
And then a couple application classes:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = false)
class SecurityConfiguration
extends CustomTypesGlobalMethodSecurityConfiguration {
private final ApplicationContext applicationContext;
private final ConversionService conversionService;
public SecurityConfiguration(
#Autowired final ApplicationContext applicationContext,
#Autowired final ConversionService conversionService
) {
this.applicationContext = applicationContext;
this.conversionService = conversionService;
}
#Override
protected ApplicationContext applicationContext() {
return applicationContext;
}
#Override
protected ConversionService conversionService() {
return conversionService;
}
}
And finally the conversion service configuration:
#Configuration
class ConversionConfiguration {
#Bean
public ConversionService conversionService() {
final DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(FooBar.class, Boolean.class, FooBar::mayProceed);
return conversionService;
}
}
The code above makes #PreAuthorize to understand FooBar-returning expressions.