How to get 'messageSource' in src/groovy correctly? - spring

I need to get the messageSource in a class in src\groovy. This class is used in UrlMappings.groovy, and at the stage I'm using this class the application is not completely started yet.
Currently I'm using the following and it works:
MessageSource messageSource = ApplicationHolder.application.mainContext.getBean('messageSource')
String message = messageSource.getMessage("code", null, "default", locale)
But the ApplicationHolder is deprecated, is there a way to achieve the same goal without using ApplicationHolder?
//I'm using Grails 2.0.1

From my limited experience, I found that the simplest approach to get the messageSource in a POGO is simply:
Holders.applicationContext.getBean("messageSource")
The other approaches I tried (implementing MessageSourceAware or adding #Component/#Autowired annotations) caused other complications.

try this:
grails.util.GrailsWebUtil.currentApplication().mainContext.messageSource

The recommended way seems to be http://burtbeckwith.com/blog/?p=1017
I.e. create a singleton bean in src/groovy which implements ApplicationContextAware, and then configure it's factoryMethod attribute in grails-app/conf/spring/resources.groovy.

I never like using Singletons which is what Holders, GrailsWebUtil, etc are doing. Instead you can just have grailsApplication injected in your service by doing:
class SomeService {
def grailsApplication
...
}
Then use that to get a message rendered:
String message = grailsApplication.mainContext.getMessage(err, Locale.getDefault()).
Viola take any FieldError, ObjectError, or code and render a message from it.

Related

Replacing micronaut's default KafkaProducerFactory with custom factory implementation

I need to customize the default KafkaProducerFactory (or any other default factory, say KafkaConsumerFactory) that ships with micronaut-kafka dependency. For that I tried to replace the existing factory using,
#Factory
#Replaces(factory = KafkaProducerFactory.class)
class CustomFactory extends KafkaProducerFactory {
#Bean
#Any
public <K, V> Producer<K, V> getProducer(
#Nullable InjectionPoint<KafkaProducer<K, V>> injectionPoint,
#Nullable #Parameter AbstractKafkaProducerConfiguration<K, V> producerConfiguration) {
validate(producerConfiguration); //this is my primary intension
super.getProducer(injectionPoint, producerConfiguration);
}
}
But it seems that Micronaut is not able to replace KafkaProducerFactory hence both the factory exists and I am getting error saying
"multiple candidate bean exists [CustomFactory, KafkaProducerFactory]"
I also thought to exclude the KafkaProducerFactory while the application loads, but could not find anything similar to Spring's ComponentScan.excludeFilter in Micronaut.
Is there anything wrong in my configuration or is there any other way to achieve the same?
Finally I got the answer. Let me elaborate little more for the actual context,
Problem
We have custom way of creating producer/consumer instances i.e. a custom class that creates those given the config properties. Now I had to modify the default factories so that instead of creating the instances on its own, the factory should invoke our custom class to instantiate producer/consumers.
Solution
I had to add #Primary along with other annotations and its working,
#Factory
#Replaces(factory = KafkaProducerFactory.class)
#Primary
class CustomFactory extends KafkaProducerFactory {
//code here
}
But the way I acheived this is kind of a work around because,
my primary intension was to override the producer/consumer creation part of default factory in a sub class and then replacing the default factory by the sub class. But as per the code structure in default factory class, it was not a single place where we can plug our custom code (no specific public method present consolidating the code for creating producer/consumer, it was being created from 3 separate places with "new") to create the producer. Hence we had to copy the entire default factory class and replaced the 3 places with custom code which does not seem to be a correct way.

Injection of bean inside ClientHeadersFactory doesn't work

I'm building a Quarkus app which handles http requests with resteasy and calls another api with restclient and I need to propagate a header and add another one on the fly so I added a class that implements ClientHeadersFactory.
Here's the code:
#ApplicationScoped
public abstract class MicroServicesHeaderHandler implements ClientHeadersFactory {
#Inject
MicroServicesConfig config;
#Override
public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders,
MultivaluedMap<String, String> clientOutgoingHeaders) {
// Will be merged with outgoing headers
return new MultivaluedHashMap<>() {{
put("Authorization", Collections.singletonList("Bearer " + config.getServices().get(getServiceName()).getAccessToken()));
put("passport", Collections.singletonList(incomingHeaders.getFirst("passport")));
}};
}
protected abstract String getServiceName();
My issue is that the injection of the config doesn't work. I tried both with #Inject and #Context, as mentioned in the javadoc of ClientHeadersFactory. I also tried to make the class non abstract but it doesn't change anything.
MicroServicesConfig is a #Startup bean because it needs to be initialized before Quarkus.run() is called, otherwise the hot reload doesn't work anymore, since it's required to handle requests.
Here's the code FYI:
#Getter
#Startup
#ApplicationScoped
public final class MicroServicesConfig {
private final Map<String, MicroService> services;
MicroServicesConfig(AKV akv, ABS abs) {
// some code to retrieve an encrypted file from a secure storage, decrypt it and initialize the map out of it
}
It appears to be an issue with ClientHeadersFactory because if I inject my bean in my main class (#QuarkusMain), it works. I'm then able to assign the map to a public static map that I can then access from my HeaderHandler with Application.myPublicStaticMap but that's ugly so I would really prefer to avoid that.
I've searched online and saw several people having the same issue but according to this blogpost, or this one, it should work as of Quarkus 1.3 and MicroProfile 3.3 (RestClient 1.4) and I'm using Quarkus 1.5.2.
Even the example in the second link doesn't work for me with the injection of UriInfo so the issue doesn't come from the bean I'm trying to inject.
I've been struggling with this for weeks and I'd really like to get rid of my workaround now.
I'm probably just missing something but it's driving me crazy.
Thanks in advance for your help.
This issue has finally been solved in Quarkus 1.8.

Configuring Spring MockMvc to use custom argument resolver before built-in ones

I have a straightforward test case. I have a controller which has a parameter of a type Spring doesn't support by default, so I wrote a custom resolver.
I create the mock mvc instance I'm using like so:
mvc = MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new GoogleOAuthUserResolver()).build();
However, Spring is also registering almost 30 other argument resolvers, one of which is general enough that it is getting used to resolve the argument before mine. How can I set or sort the resolvers so that mine is invoked first?
This worked for me without reflection:
#RequiredArgsConstructor
#Configuration
public class CustomerNumberArgumentResolverRegistration {
private final RequestMappingHandlerAdapter requestMappingHandlerAdapter;
#PostConstruct
public void prioritizeCustomArgumentResolver () {
final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(Objects.requireNonNull(requestMappingHandlerAdapter.getArgumentResolvers()));
argumentResolvers.add(0, new CustomerNumberArgumentResolver());
requestMappingHandlerAdapter.setArgumentResolvers(argumentResolvers);
}
}
The issue was that the People class the Google OAuth library I am using extends Map and the mock servlet API provides no way to manipulate the order in which the handlers are registered.
I ended up using reflection to reach into the mocks guts and remove the offending handler.

Null Pointer Exception In Spring Proxy Class and Kotlin

I am facing some problems with kotlin in conjunction with spring.
I have a controller bean (without an interface btw) which has an auto-wired service bean via the primary constructor.
It works perfectly unless I use caching annotations for the controller. Apparently springs caching generates a proxy class under the hood which deals with the caching.
My code looks like this:
#RestController
#RequestMapping("/regions/")
open class RegionController #Autowired constructor(val service: RegionService) {
#RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
#Cacheable(cacheNames = arrayOf("regions"))
fun get(#PathVariable id: Long): RegionResource {
return this.service.get(id)
}
}
The problem now is a null pointer exception when the method is executed, actually this.service is null which technically is not possible as it is a nonnull variable in kotlin.
I assume that class proxies generated by spring initialize the class with null values instead of the autowired bean. This must be a common pitfall using kotlin and spring. How did you circumvent this problem?
In Kotlin both classes and members are final by default.
For the proxying library (CGLIB, javaassist) to be able to proxy a method it has to be declared non final and in a non final class (since those libraries implement proxying by subclassing). Change your controller method to:
#RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
#Cacheable(cacheNames = arrayOf("regions"))
open fun get(#PathVariable id: Long): RegionResource {
return this.service.get(id)
}
You probably see a warning in console regarding RegionController methods not being subject to proxying.
The Kotlin compiler plugin
The Kotlin team has acknowledged this difficulty and created a plugin that marks the standard AOP proxy candidates e.g. #Component with open.
You can enable the plugin by in your build.gradle:
plugins {
id "org.jetbrains.kotlin.plugin.spring" version "1.1.60"
}
Soon this might not be a problem any longer.
There is work in progress that any lib (including spring for example) can specify a list of annotations a file in META-INF. Once a class is annotated with one of these, it will default to open for the class itself and all its functions. This is also true for classes inheriting from an annotated class.
For more details, have a look at https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204

i18n translation in JSP custom tag

Is it possible to write a custom JSP tag to take an i18n message key and output the translation phrase for the given request?
Normally in JSP/JSTL, I do:
<fmt:message key="${messageKey}"><fmt:param>arg1</fmt:param></fmt:message>
And I get the translation phrase. Now I need to do the following (there's a good reason for this):
<custom:translate key="${messageKey}" arg="arg1"/>
But I don't know how to look up the translation in the custom tag code. The TagSupport base class provides a pageContext from which I can get a ServletRequest which has the Locale... but how do I then look up the translation for a key?
I use Spring 3.0 and in my application-context.xml, I've defined a ReloadableBundleMessageSource so I can call:
messageSource.getMessage(
key, new Object[] {arg}, pageContext.getRequest().getLocale()
);
but I don't think I can inject messageSource into a custom tag, can I? Otherwise I can instantiate a new one, but would it load my tens of thousands of translations for every call? I don't want to resort to making messageSource a static member of a static class.
I don't do Spring, but in "plain" JSP you can just put the ResourceBundle instance in the session scope with help of a Filter or Servlet
ResourceBundle bundle = ResourceBundle.getBundle(basename, request.getLocale());
request.getSession().setAttribute("bundle", bundle);
And treat it in JSP like any other bean in EL.
${bundle[messageKey]}
It must be possible to have Spring to put that as a bean in the session scope.
There is a utility in spring to access the web application context. Then you can look up a bean by its name or type.
To get hold of your resource bundle, you could do something like:
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(pageContext.getServletContext());
messageResource = springContext.getBean("messageResource");
This question is very old but I think it is worth to share another way to solve this.
To access the Spring message source in a custom tag you only need to extend the class org.springframework.web.servlet.tags.RequestContextAwareTag instead of TagSupport.
In this case you have to implement the method doStartTagInternal() instead of doStartTag(), but inside this method you will have access to the MessageSource through getRequestContext().getMessageSource() method.
Therefore, your class would look like:
public class CreateCustomFieldTag extends RequestContextAwareTag{
//variables (key, arg...), getters and setters
#Override
protected int doStartTagInternal() throws Exception {
getRequestContext().getMessageSource().getMessage(
key, new Object[] {arg}, getRequestContext().getLocale());
}
}

Resources