Quarkus - #ConfigMapping: built-in way to show all properties like "toString()", instead of manual building - quarkus

As #ConfigMapping uses interfaces, there are no ways to implement toString(); I cannot view all values and nested values without a lot of manual work(reflection and switch case to deal with each type).
Any plan to support easy view of all levels of properties? Like a super class to inherit which handles this manual toString() like building?
In SmallRye config doc page I read this:
ToString#
If the config mapping contains a toString method declaration, the config mapping instance will include a proper implementation of the toString method.
But I added #Override String toString(); method everywhere, Quarkus just complains about cannot find property "to_string".
OK I found this issue which is implemented in this commit, which exactly adds the sentence I read into the doc; but still not very clear to me.

Adding a String toString() method in your #ConfigMapping will generate the expected toString() implementation.
This is only available starting from SmallRye Config 2.11.0 and Quarkus 2.12.0.Final, which came out just a few weeks ago. Previous versions will just try to resolve the method as a configuration property. From your description, it seems that is the case, so you may be using an older Quarkus version that does not support this feature yet.

Related

List<List<String>> mapped to List<String>

I'm learning how to use Mapstruct in a Spring Boot and Kotlin project.
I've got a generated DTO (ThessaurusDTO) that has a List and I need this mapped into a List on my model (Vocab).
It makes sense that MapStruct can't map this automatically, but I know for a fact that the first list will always be size = 1. I have no control on the API the DTO model belongs to.
I found on the documentation that I can create define a default method implementation within the interface, which would loosely translate to a normal function in Kotlin
My mapper interface:
#Mapper
interface VocabMapper {
#Mappings(
// ...
)
fun thessaurusToVocab(thessaurusDTO: ThessaurusDTO): Vocab
fun metaSyns(nestedList: List<List<String>>): List<String>
= nestedList.flatten()
}
When I try to do a build I get the following error:
VocabMapper.java:16: error: Can't map collection element "java.util.List<java.lang.String>" to "java.lang.String ". Consider to declare/implement a mapping method: "java.lang.String map(java.util.List<java.lang.String> value)".
It looks like mapStruct is still trying to automatically do the mapping while ignoring my custom implementation. Am I missing something trivial here?
I found on the documentation that I can create define a default method implementation within the interface, which would loosely translate to a normal function in Kotlin
From my understand of what I found online, Kotlin does not properly translate an interface function into a default method in Java, but actually generates a class that implements the interface.
If that's the problem, you can annotate metaSyns with #JvmDefault:
Specifies that a JVM default method should be generated for non-abstract Kotlin interface member.
Usages of this annotation require an explicit compilation argument to be specified: either -Xjvm-default=enable or -Xjvm-default=compatibility.
See the link for the difference, but you probably need -Xjvm-default=enable.
I've seen to have fixed this by relying on an abstract based implementation, instead of using an interface.
From my understand of what I found online, Kotlin does not properly translate an interface function into a default method in Java, but actually generates a class that implements the interface.
https://github.com/mapstruct/mapstruct/issues/1577

Are Thymeleaf model attributes not allowed to start with 'is'?

So I'm writing a springboot application and came across a weird behaviour: If a property name start with is, for example: isIgnoreRequest thymeleaf won't find it but if i change it to ignoreRequest it works.
So my question is: Am I not allowed to have is at the beginning?
Here is some more context:
data class Response(val isIgnoreRequest: Boolean = false,
val name: String = StringUtils.EMPTY)
...
//This is how I add the attribute
//Info = Response object
redirectAttributes.addFlashAttribute(ATTRIBUTE_RESPONSE, info)
With the code above thymeleaf can't find the property:
Property or field 'isIgnoreRequest' cannot be found on object of type ... - maybe not public or not valid?
If I remove the is it works fine. Even though it sounds stupid I think the is is indeed my problem.
Yes, the model attributes can start with is. The issue isn't coming from thymeleaf, but from kotlin (nice job putting it in the tags). Let me explain:
When you reference a model attribute in thymeleaf, it looks for the getter/setter method of that attribute using the normal convention; in your example, for the attribute isIgnoreRequest, thymeleaf will look for the methods getIsIgnoreRequest and setIsIgnoreRequest.
What happens is kotlin generates the getters and setters for isXXX booleans in a different way than the standard, and thymeleaf fails when calling them with the standard syntax. You can see more on how kotlin generates the getters and setters for booleans in
https://github.com/sockeqwe/fragmentargs/issues/46 or
https://github.com/sockeqwe/sqlbrite-dao/issues/27
As to solve your issue, the best solution is probably naming your attributes in a different way so that kotlin doesn't mess with the standard for generating getter and setter methods (which IMO only complicates things unnecessarily; although some frameworks like JSF had a similar issue with isXXX booleans since forever).

How to map service factory PIDs to their `ObjectClassDefinition`

In OSGi R6 I desire to programmatically validate user-supplied String configuration properties plus a service factory PID against what is supported by whatever configurable #Component (or ManagedServiceFactory) that declares it configures this PID, e.g. #Component(configurationPid=some.service.factory.pid, ...). Additionally, I want to somehow convert valid String properties to their appropriate property types. Looking through the OSGi Compendium, it seems the Metatype Service is what I'm looking for.
If that's correct, given the following:
Applicable components uses component property types to specify their configuration
Component property types are annotated with #ObjectClassDefinition
Components are annotated with #Designate, mapping it to the applicable #ObjectClassDefinition
Is this the most straightfoward way to map factory PIDs to their ObjectClassDefinition:
Call BundleContext.getBundles(). For each bundle, call MetaTypeService.getMetaTypeInformation(Bundle).
For each returned MetaTypeInformation call MetaTypeInformation.getFactoryPids() and filter on the factory PIDs I care about.
For applicable MetaTypeInformation, call MetaTypeInformation.getObjectClassDefinition(String, String) to obtain the ObjectClassDefinition, using either a default or specific locale.
(Tangential, the above seems expensive to perform each time, so caching bundle IDs, mapping them to associated factory PIDs, and keeping the cache up-to-date somehow seems appropriate.)
Or, is there some other OSGi magic that can be programmatically queried with a service factory PID, which returns something that gets to some ObjectClassDefinition quicker than the above process?
Update 1
Stepping back, I'm writing a CRUD-wrapper around ConfigurationAdmin for each of my configurable components. I'm trying to avoid createFoo, deleteFoo, updateFoo, createBar, ... My application happens to be amenable to URIs. So my working approach was to use Metatype Service, pass in a parsed URI query (Map<String, List<String>>), and then utilize Metatype Service to validate and reconstruct these values, circling back to the OP. (On the side, seems like a not-pretty hack to me.)
Another approach was to use aQute.bnd.annotations.metatype.Configurable.createConfigurable(Class, Map), which I preferred more! Until I saw this bnd GitHub comment:
The bnd metatype annotations are deprecated in bnd 3.2 and will be removed in bnd 4.0. These annotations are replaced by the OSGi metatype annotations.
So I didn't want to rely on that package if it's going away soon. I looked at what Felix does and didn't want to use their equivalent Configurable class. I'm all ears on different approaches!
Update 2
Reducing this more, I'd like to validate potentially user-supplied key/values configuration properties to ensure they're applicable for some configuration pid, prior to calling ConfigurationAdmin.createFactoryConfig. Maybe this is overkill?
I once created a class that takes the configuration class, creates a proxy, and then uses this proxy to get the name of the method and the type. It was used something like this:
ConfigHelper<Config> helper = new ConfigHelper( Config.class, "my.pid");
int port = helper.get().port(); // get the configuration
helper.set( helper.get().port(), 1000);
helper.update();
The proxy you get from the get would record the method when one of the methods is called. On the set method it would use the last called proxy method to identify the property. It would then convert the given value to the property type based on the method's return value. The bnd converter is ideal for this but I think Felix now has a standard OSGi converter. (Which is based on the ideas of the bnd converter.)
The method name is then used as the property. The name mangling necessary is defined in an OSGi spec. This allows you to use underscores, Java keywords, and dotted names.
So this would allow you to roundtrip configurations. No worry about the types, they will automatically fall in their place.
Updated This is updated after I understood the question better
Updated 2 Added an example at https://github.com/aQute-os/biz.aQute.osgi.util/tree/master/biz.aQute.osgi.configuration.util

FreeMarker Complex Collection

I've got a HashMap as Map<Long, List<Map<String, Object>>> typeAndKno, in the FreeMarker page, I get the content of this map like this:
<#list typeAndKno?keys as typeId>
${typeAndKno.get(typeId).get(0).get('TYPE_NAME')}
<#list typeAndKno.get(typeId) as kno>
${kno.get('KNOWLEDGE_ID')}
</#list>
</#list>
This code works fine in Struts2, but after moved to Spring MVC, the code fails. I finally changed the code to this:
<#list typeAndKno?keys as typeId>
${typeAndKno[typeId]?first['TYPE_NAME']}
<#list typeAndKno[typeId?string] as kno>
${kno['KNOWLEDGE_ID']}
</#list>
</#list>
What's the difference between these two pieces of code? Is there a way to make the first piece of code work in Spring MVC?
Update:
As of 2.3.22 there's a much easier and non-disruptive solution for this: configure FreeMarker so that ?api works, and then you can use the Java API of Map where the keys aren't String-s. See this FAQ entry or this answer for more details.
And Strut's FreeMarker setup is something that's strongly discouraged now. Of course, back then, when they did that, that was maybe the most reasonable workaround, but it isn't anymore for a while, and especially not since 2.3.22.
Old answer (outdated):
The way you see Java objects from templates depends on the ObjectWrapper used, which is a FreeMarker configuration setting. Based on your example, Struts uses a BeansWrapper with its default settings, while Spring possibly uses the DefaultObjectWrapper. So that causes the differences. I wouldn't recommend using either, because:
With BeansWrapper with its default settings Map keys mix with the method names, with method names having priority. Surely you can safely use myMap.get(key) to get around that, but myMap.get('foo') is just horrible compared to myMap.foo, which will only work as far you have no method called foo. Also ?keys will return a mixture of real keys and method names with it... it's a mess.
With DefaultObjectWrapper you can safely write myMap.foo, but you won't be able to get entities with non-string keys, because myMap[key] only support strings, and you don't have myMag.get(key) anymore.
So what I have usually used with FreeMarker was a bw = new BeansWrapper(); bw.setSimpleMapWrapper(true). With this, the methods of Map-s are not visible, just like with DefaultObjectWrapper, so you can use myMap.foo and myMap[key] safely. But if rarely you need to get something with a non-string key, you can use myMap(nonStringKey) (yes, with () instead of []). This last doesn't work with DefaultObjectWrapper. (Hopefully FreeMarker 2.4 will solve this mess with non-string keys nonsense, but it's not like it will be out anytime soon...)
So the next question is how to set the object wrapper with Spring. I'm not at home there. As far as I see, you have a FreeMarkerConfigurer bean which has a freemarkerSettings property, which is a Properties object that's eventually is passed to FreeMarker's Properties-based configuration API. So there you should be able add an object_wrapper property that refers to the class name of the ObjectWrapper to use (or it could just be beans to use the default BeansWrapper instance like maybe Struts does). Problem is, the property-based API is rather limited, and so you can't both create and configure (call setSimpleMapWrapper) a BeansWrapper there. You could do that in the spring configuration file of course, but I don't see a way to inject that into the FreeMarkerConfigurer, unless you create the whole freemarker.template.Configuration object as a bean, and inject that into the FreeMarkerConfigurer with the configuration property of it. So maybe the easiest workaround is extending BeansWrapper to override the default of simpleMapWrapper, and then referring to the class of that extending class via object_wrapper. (Just in case somebody reads this later, it's probable that FreeMarker 2.3.21 will extended the properties configuration API so that you can just set object_wrapper to BeansWrapper() { simpleMapWrapper = true }.)

How to add a custom ContentHander for JAXB2 support in Spring 3 (MVC)?

Scenario: I have a web application that uses Spring 3 MVC. Using the powerful new annotations in Spring 3 (#Controller, #ResponseBody etc), I have written some domain objects with #XML annotations for marhalling ajax calls to web clients. Everything works great. I declared my Controller class to have a return type #ResponseBody with root XML object - the payload gets marshalled correctly and sent to Client.
The problem is that some data in the content is breaking the XML compliance. I need to wrap this with CDATA when necessary. I saw a POST here How to generate CDATA block using JAXB? that recommends using a custom Content Handler. Ok, fantastic!
public class CDataContentHandler extends (SAXHandler|XMLSerializer|Other...) {
// see http://www.w3.org/TR/xml/#syntax
private static final Pattern XML_CHARS = Pattern.compile("[<>&]");
public void characters(char[] ch, int start, int length) throws SAXException {
boolean useCData = XML_CHARS.matcher(new String(c,start,length)).find();
if (useCData) super.startCDATA();
super.characters(ch, start, length);
if (useCData) super.endCDATA();
}
}
Using Spring MVC 3, how do I achieve this? Everything was "auto-magically" done for me with regards to the JAXB aspects of setup, Spring read the return type of the method, saw the annotations of the return type and picked up JAXB2 off the classpath to do the marshalling (Object to XML conversion). So where on earth is the "hook" that permits a user to register a custom Content Handler to the config?
Using EclipseLink JAXB implementation it is as easy as adding #XmlCDATA to the Object attribute concerned. Is there some smart way Spring can help out here / abstract this problem away into a minor configuration detail?
I know Spring isn't tied to any particular implementation but for the sake of this question, please can we assume I am using whatever the default implementation is. I tried the Docs here http://static.springsource.org/spring-ws/site/reference/html/oxm.html but it barely helped at all with this question from what I could understand.
Thanks all for any replies, be really appreciated.
Update:
Thanks for the suggested answer below Akshay. It was sufficient to put me on right tracks. Investigating further, I see there is a bit of history with this one between Spring version 3.05 and 3.2. In Spring 3.05 it used to be quite difficult to register a custom MessageConverter (this is really the goal here).
This conversation pretty much explains the thinking behind the development changes requested:
https://jira.springsource.org/browse/SPR-7504
Here is a link to the typically required class override to build a cusom solution:
http://static.springsource.org/spring/docs/3.1.0.M1/javadoc-api/org/springframework/http/converter/AbstractHttpMessageConverter.html
And the following Question on stack overflow is very similar to what I was asking for (except the #ResponseBody discussion relates to JSON and jackson) - the goal is basically the same.
Spring 3.2 and Jackson 2: add custom object mapper
So it looks like usage of , and overriding MarshallingHttpMessageConverter is needed, registering to AnnotationMethodHandlerAdapter. There is a recommended solution in link above to also get clever with this stuff and wrap the whole thing behind a custom defined Annotation.
I haven't yet developed a working solution but since I asked the questions, wanted to at least post something that may help others with the same sort of question, to get started. With all due respect, although this has all improved in Spring 3.2, it's still bit of a dogs dinner to get a little customization working... I really was expecting a one liner config change etc.
Rather than twist and bend Spring, perhaps the easiest answer for my particular issue is just to change JAXB2 implementation and use something like Eclipse Link JAXB that can do this out of the box.
Basically you need to create a custom HttpMessageConverter. Instead of relying on the Jaxb2RootElementHttpMessageConverter that spring uses by default.
Unfortunately, customizing one converter means you are telling spring that you will take care of loading all the converters you need! Which is fairly involved and can get complicated, based on whether you use annotations, component scanning, Spring 3.1 or earlier, etc.. The issue of how to add a custom converter is addressed here: Custom HttpMessageConverter with #ResponseBody to do Json things
In your custom message converter you are free to use any custom JAXB2 content handlers.
Another, simpler approach to solve your original problem would be to use a custom XmlJavaTypeAdapter. Create a custom implementation of javax.xml.bind.annotation.adapters.XmlAdapter to handle CDATA, in the marshal method wrap the return value with the cdata braces. Then in your mapped pojo, use the XmlAdapter annotation, pass it the class of your custom adapter and you should be done.
I have not myself implemented the adapter approach, so couldn't provide sample code. But it should work, and won't be a lot of work.
Hope this helps.

Resources