After upgrading to Spring Boot 1.3 (via Grails 3.1), the JSON output is rendered incorrectly. I believe it is because of the new auto-configured WebSocket JSON converter.
For example, with previous versions of Spring Boot (via Grails 3.0), using the following code:
#MessageMapping("/chat")
#SendTo("/sub/chat")
protected String chatMessage() {
def builder = new groovy.json.JsonBuilder()
builder {
type("message")
text("foobar")
}
builder.toString()
}
This would produce:
{"type": "message", "text": "foobar"}
With Spring Boot 1.3 (via Grails 3.1), that web socket produces the following:
"{\"type\":\"message\",\"text\":\"foobar\"}"
This is not valid JSON. How can I get rid of this new behavior and have it render the JSON as it was before? Please let me know if you have any suggestions.
I tried overriding the new configureMessageConverters method, but it did not have any effect.
looks like you are right. referenced commit shows questionable autoconfiguration imho.
especially b/c in the past, the converter ordering was intentionally changed to that StringMessageConverter takes precedence before MappingJackson2MessageConverter: https://github.com/spring-projects/spring-framework/commit/670c216d3838807fef46cd28cc82165f9abaeb45
for now, you can either disable that autoconfiguration:
#EnableAutoConfiguration(exclude = [WebSocketMessagingAutoConfiguration])
class Application extends GrailsAutoConfiguration { ... }
or, you add yet another StringMessageConverter to the top of the configured converters (maybe because you do want the boot autoconfiguration behavior because it is using the jackson ObjectMapper bean instead of creating a new one):
#Configuration
#EnableWebSocketMessageBroker
class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add 0, new StringMessageConverter()
return true
}
...
}
hope that helps.
I don't know how to do it in Grails but in Java you have to now pass the object instead of an object in the String class. I believe the old behavior was actually incorrect as it was returning a string as an object so there was no way to return a String that had JSON inside it as a String. So create an object with the structure you want and return it and you should be fine. I went through the same issue when upgrading from 1.2.X to 1.3.X. I am not exactly sure what change caused this but I think in the long run it is the correct thing to do.
Related
I'm running into a problem with my Elasticsearch Document index creation failing on startup with "java.lang.IllegalArgumentException: can't add a _parent field that points to an already existing type, that isn't already a parent". I'm not sure if this is due to a version upgrade or b/c I am starting with a brand new Elasticsearch server install.
Contrived example that shows what I'm seeing:
// UserSearchResult.java
#Document(indexName = "hr_index", type = "user")
public class UserSearchResult implements Serializable {
...
#Field(type=FieldType.keyword)
#Parent(type="department")
private String departmentCode;
...
}
// DepartmentSearchResult.java
#Document(indexName = "hr_index", type = "department")
public class DepartmentSearchResult implements Serializable {
...
}
When I start my application I get that exception. If I check the ElasticSearch server, I see the "hr_index" index and the "department" mapping, but the "user" mapping is not created.
If I understand the error, it's because "department" is being created and then when Spring tries to create "user" with "department" as its parent, it doesn't like that, since department wasn't previously marked as a parent when it was created.
Is there some way (via annotation?) to denote DepartmentSearchResult as being a parent when it's created somehow?
Or, is it possible to give a hint to Spring Data Elasticsearch as to what order it should create the indices/mappings? I have seen some other posts (Spring Data Elasticsearch Parent/Child Document Repositories / Test execution error) but disabling auto creation and then manually creating it myself (either as part of my Spring codebase or external to the app) seems kind of "un-Spring-y" to me?
Or, is there some other approach I should be taking?
(This is a working Spring application that had been using Spring 4.2.1 and Spring Data Release Train Gosling, that I'm attempting to upgrade to use Spring 5.0.0 and Spring Data Release Train Kay. As part of this I am starting with a fresh Elasticsearch install, and so I'm not sure if this error is coming from the upgrade or just b/c the install is clean).
In the SD ES, issues related to the parent-child relationship at now really poorly developed.
The problem is most likely due to the fact that you are using a clean installation of Elasticsearch. Before the update, the problem did not arise, because mappings have already been created. For the solution, you can use elasticsearchTemplate, which is part of SD ES, and ApplicationListener. It's simple. Just 3 steps.
Drop index in ES (it only needs one time):
curl -XDELETE [ES_IP]:9200/hr_index
Tell SD ES not to create indices and mappings automatically
// UserSearchResult.java
#Document(indexName = "hr_index", type = "user", createIndex = false)
public class UserSearchResult implements Serializable {
...
#Field(type=FieldType.keyword)
#Parent(type="department")
private String departmentCode;
...
}
// DepartmentSearchResult.java
#Document(indexName = "hr_index", type = "department", createIndex = false)
public class DepartmentSearchResult implements Serializable {
...
}
Add a ApplicationListener:
#Component
public class ApplicationStartupListener implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private ElasticsearchTemplate elasticsearchTemplate;
//Mapping for child must be created only if mapping for parents doesn't exist
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
elasticsearchTemplate.createIndex(DepartmentSearchResult.class);
try {
elasticsearchTemplate.getMapping(DepartmentSearchResult.class);
} catch (ElasticsearchException e) {
elasticsearchTemplate.putMapping(UserSearchResult.class);
elasticsearchTemplate.putMapping(DepartmentSearchResult.class);
}
}
}
P.S. Among other things, it is worth paying attention to the fact that with the release of ES 5.6, a process for removing types began. This inevitably entails the removal of the parent-child relationship. In one of the next releases of the SD ES, we will provide the opportunity to work with joins. Working with parent-child relationships is unlikely to be improved
I am new to grails and while working with Spring Security LDAP plugin it was identified that it accepts the ldap server password in plain text only. The task in hand is to pass an encrypted password which is decrypted before it is consumed by the plugin during its initialization phase.
I have already searched for all possible blogs and stackoverflow questions but could not find a way to extend the main plugin class to simply override the doWithSpring() method so that i can simply add the required decryption logic for the Ldap server password. Any help here will be appreciated.
I have already seen and tried jasypt plugin but it also does not work well if the password is stored in some external file and not application yml. So I am looking for a solution to extend the Spring security plugin main class, add the required behavior and register the custom class.
EDIT
Adding the snippet from Grails LDAP Security plugin, which I am trying to override. So If i am successfully able to update the value of securityConfig object before the plugin loads, the purpose is solved.
Some snippet from the plugin:
def conf = SpringSecurityUtils.securityConfig
...
...
contextSource(DefaultSpringSecurityContextSource, conf.ldap.context.server) { // 'ldap://localhost:389'
authenticationSource = ref('ldapAuthenticationSource')
authenticationStrategy = ref('authenticationStrategy')
userDn = conf.ldap.context.managerDn // 'cn=admin,dc=example,dc=com'
**password = conf.ldap.context.managerPassword // 'secret'**
contextFactory = contextFactoryClass
dirObjectFactory = dirObjectFactoryClass
baseEnvironmentProperties = conf.ldap.context.baseEnvironmentProperties // none
cacheEnvironmentProperties = conf.ldap.context.cacheEnvironmentProperties // true
anonymousReadOnly = conf.ldap.context.anonymousReadOnly // false
referral = conf.ldap.context.referral // null
}
ldapAuthenticationSource(SimpleAuthenticationSource) {
principal = conf.ldap.context.managerDn // 'cn=admin,dc=example,dc=com'
**credentials = conf.ldap.context.managerPassword // 'secret'**
}
You don't need to override the doWithSpring() method in the existing plugin. You can provide your own plugin which loads after the one you want to affect and have your doWithSpring() add whatever you want to the context. If you add beans with the same name as the ones added by the other plugin, yours will replace the ones provided by the other plugin as long as you configure your plugin to load after the other one. Similarly, you could do the same think in resources.groovy of the app if you don't want to write a plugin for this.
You have other options too. You could write a bean post processor or bean definition post processor that affects the beans created by the other plugin. Depending on the particulars, that might be a better idea.
EDIT:
After seeing your comment below I created a simple example that shows how you might use a definition post processor. See the project at https://github.com/jeffbrown/postprocessordemo.
The interesting bits:
https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomeBean.groovy
package demo
class SomeBean {
String someValue
}
https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomePostProcessor.groovy
package demo
import org.springframework.beans.BeansException
import org.springframework.beans.MutablePropertyValues
import org.springframework.beans.PropertyValue
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
class SomePostProcessor implements BeanDefinitionRegistryPostProcessor{
#Override
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition definition = registry.getBeanDefinition('someBean')
MutablePropertyValues values = definition.getPropertyValues()
PropertyValue value = values.getPropertyValue('someValue')
def originalValue = value.getValue()
// this is where you could do your decrypting...
values.addPropertyValue('someValue', "MODIFIED: ${originalValue}".toString())
}
#Override
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/conf/spring/resources.groovy
beans = {
someBean(demo.SomeBean) {
someValue = 'Some Value'
}
somePostProcessor demo.SomePostProcessor
}
https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/init/postprocessordemo/BootStrap.groovy
package postprocessordemo
import demo.SomeBean
class BootStrap {
SomeBean someBean
def init = { servletContext ->
log.info "The Value: ${someBean.someValue}"
}
def destroy = {
}
}
At application startup you will see log output that looks something like this...
2017-10-23 19:04:54.356 INFO --- [ main] postprocessordemo.BootStrap : The Value: MODIFIED: Some Value
The "MODIFIED" there is evidence that the bean definition post processor modified the property value in the bean. In my example I am simply prepending some text to the string. In your implementation you could decrypt a password or do whatever you want to do there.
I hope that helps.
After trying Jasypt plugin and BeanPostProcessor solutions unsuccessfully for my use case, I found below solution to work perfectly.
To describe again the problem statement here,
a) we had to keep the passwords in an encrypted format inside properties files
b) and given we were packaging as a war file so the properties must not be kept inside the war to allow automated deployment scripts update the encrypted passwords depending on the environment
Jasypt plugin was a perfect solution for the use case a), but it was not able to cover the b) scenario
Moreover, the Grails LDAP Security plugin was getting loaded quite early hence Bean Post processors were also not helping out here.
Solution:
Created a new class by implementing the interface SpringApplicationRunListener. Extended its methods and parsed the properties file using YamlPropertySourceLoader
Sample code:
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
PropertySource<?> applicationYamlPropertySource = loader.load(
"application.yml", new ClassPathResource("application.yml"),"default");
return applicationYamlPropertySource;
Once the properties were loaded inside the MapPropertySource object, parsed them for the encrypted values and applied the decryption logic.
This whole implementation was executed before any plugins were initialized during Grails bootup process solving the purpose.
Hope it will help others.
Using JSF 2 on JBoss AS 7
Getting the following error:
07:36:39,579 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (http-/172.20.91.126:12580-16)
Error Rendering View[/views/afgarendesok.xhtml]:
com.sun.faces.mgbean.ManagedBeanCreationException:
Unable to set property searchManager for managed bean afgArendeBacking
at com.sun.faces.mgbean.ManagedBeanBuilder$BakedBeanProperty.set(ManagedBeanBuilder.java:615)
The searchManager property is defined in the AfgArendeBacking class as:
#ManagedProperty(value="#{afgArendeSokManager}")
private AfgArendeSokManager searchManager;
#Override
public AfgArendeSokManager getSearchManager() {
return searchManager;
}
public void setSearchManager(AfgArendeSokManager searchManager) {
this.searchManager = searchManager;
}
The AfgArendeSokManager is a #ManagedBean that is #SessionScoped.
Two things I don't get. One is why the error shuts down all usage of JSF not just for the session producing the error. The error seems to appear after non-usage both below the default session timeout and beyond. The other odd this is that a null pointer exception at line 606 in the BakedBeanProperty has to be the one the writeMethod variable. That variable is created via the PropertyDescriptor.getWriteMethod() call. This should have bombed earlier when creating baked bean (i.e. bakeBeanProperty method).
Any ideas how to debug? The property "searchManager" is resolved correctly since we can use the JSF views normally (both the getter/setter exist).
The search manager is our session scratch pad for propagating stuff between view and request scoped backing beans.
The article explains the issue of using reflection to access methods with covariant return types (see here: https://dzone.com/articles/covariant-return-type-abyssal). The article relates to Java 6 but the background information is very useful.
The issue you're facing and that hit us just this week (using Java 1.7.0_40) is not one of EL but of the java.beans.Introspector.
I'm currently experimenting a little with Apache MyFaces CODI. I managed to create a simple working Typesafe-Navigation using #Page and an action Method which returns a Class.
However, when I'm adding an #PageBean-Annotation with e.g. MyPageBean.class, the following exception is thrown when I try to navigate to the page:
exception
javax.servlet.ServletException: WELD-001324 Argument bean must not be null
root cause
org.jboss.weld.exceptions.IllegalArgumentException: WELD-001324 Argument bean must not be null
The code of my page is:
#Page
#PageBean(MyPageBean.class)
public final class MyPage implements ViewConfig, Serializable {
}
and my Page-Bean:
public class MyPageBean implements Serializable {
#InitView
protected void initView() { }
#PrePageAction
protected void prePageAction() { }
#PreRenderView
protected void preRenderView() { }
}
And the Action-Method called by the Facelets Page:
public Class<? extends ViewConfig> nextPage() {
return MyPage.class;
}
Does the pageBean-Class (MyPageBean) need to have a specific annotation or interface? I already tried using #Model but this didn't change anything.
My Configuration:
Jave EE6 with Weld (created using the weld-archetype)
Glassfish 3.1 Community Edition (The one shipped with Netbeans 7)
JSF2.0 (Mojarra 2.1)
EJB 3.1
MyFaces CODI 0.9.4
RichFaces 4.0.0.Final
Thanks for any advices!
Best regards,
Robert
If you don't use any specific scope, it will end up being #Dependent.
I suggest to at least use #RequestScoped (take care, don't use the javax.faces.bean.RequestScoped, but the annontation from CDI!)
Oki, talked with Gerhard now as he has more experience with CODI on Weld.
Apparently this seems to be an error in the Weld version you use. This should be working in weld-1.1.1.Final https://github.com/weld/core/tree/1.1.1.Final
Please try to replace the weld-osgi-bundle in your glassfish with the one from weld 1.1.1.Final
cp target/weld-osgi-bundle-1.1.1.jar /opt/sun/glassfish/glassfish/modules/weld-osgi-bundle.jar
if it works: credits go to os890 ;)
In the C# language, using StructureMap 2.5.4, targeting .NET Framework 3.5 libraries.
I've taken the step to support multiple Profiles in a structure map DI setup, using ServiceLocator model with Bootstrapper activation. First setup was loading default registry, using the scanner.
Now I like to determine runtime what Registry configuration I like to use. Scanning and loading multiple assemblies with registries.
Seems it's not working for the actual implementation (Getting the 202, default instance not found), but a stripped test version does work. The following setup.
Two assemblies containing Registries and implementations
Scanning them in running AppDomain, providing the shared Interface, and requesting Creation Of Instance, using the interfaces in constructor (which get dealt with thanx to the profile on Invokation)
Working code sample below (same structure for other setup, but with more complex stuff, that get's a 202):
What type of couses are possible for a 202, specifically naming the System.Uri type, not being handles by a default type?? (uri makes no sense)
// let structure map create instance of class tester, that provides the registered
// interfaces in the registries to the constructor of tester.
public class Tester<TPOCO>
{
private ITestMe<TPOCO> _tester;
public Tester(ITestMe<TPOCO> some)
{
_tester = some;
}
public string Exec()
{
return _tester.Execute();
}
}
public static class Main {
public void ExecuteDIFunction() {
ObjectFactory.GetInstance<Tester<string>>().Exec();
}
}
public class ImplementedTestMe<TSome> : ITestMe<TSome>
{
public string Execute()
{
return "Special Execution";
}
}
public class RegistryForSpecial : Registry
{
public RegistryForSpecial()
{
CreateProfile("Special",
gc =>
{
gc.For(typeof(ITestMe<>)).UseConcreteType(typeof(ImplementedTestMe<>));
});
}
}
Background articles on Profiles I used.
How to setup named instances using StructureMap profiles?
http://devlicio.us/blogs/derik_whittaker/archive/2009/01/07/setting-up-profiles-in-structuremap-2-5.aspx
http://structuremap.sourceforge.net/RegistryDSL.htm
EDIT:
It seemed the missing interface was actually the one being determined runtime. So here is the next challange (and solved):
I provided a default object whenever StructureMap needs to create the object. Like:
x.ForRequestedType<IConnectionContext>()
.TheDefault.Is.Object(new WebServiceConnection());
This way I got rid of the 202 error, because now a real instance could be used whever structure map needed the type.
Next was the override on runtime. That did not work out at first using the ObjectFactory.Configure method. Instead I used the ObjectFactory.Inject method to overide the default instance. Works like a charm.
ObjectFactory.Inject(typeof(IConnectionContext), context);
Loving the community effort.
Error code 202 means a default instance could not be built for the requested type. Your test code is apparently not equal to your real code that fails. If you are getting an error about Uri, you likely have a dependency that requires a Uri in its constructor. It may not be the class you are asking for - it may be one of that classes dependendencies - or one of the dependencies dependencies... somewhere down the line someone is asking StructureMap to resolve a Uri, which it cannot do, without some help from you.