How do I configure the default ObjectMapper? - jackson

In light-4j config module, there is an ObjectMapper instance that is used in a lot of different places. I have a Rest/GraphQL hybrid application and want to customize the default ObjectMapper. What is the best way to do so?

The ObjectMapper instance in the config module is static variable and a static block is used to initialize it. To overwrite the configuration, you can create a startup hook to do that.
Config.getInstance().getMapper()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(MapperFeature.USE_STD_BEAN_NAMING)
.setSerializationInclusion(JsonInclude.Include.ALWAYS)
.setPropertyNamingStrategy(new CobraCase())

Related

Why ClassGraph finds classes from other deployment on Wildfly?

I prepared WAR archive and I deployed it on Wildfly 21.
I want to find all classes annotated with javax.ws.rs.ApplicationPath annotation.
try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages( PACKAGE ).scan())
{
final ClassInfoList classesWithAnnotation =
scanResult.getClassesWithAnnotation( ApplicationPath.class.getName() );
}
It finds two classes, one from my deployment and one from other deployment. I undeployed other deployment to make sure that one class is taken from it and I am sure, if only one deployment is deployed on Wildfly then it return only one class.
I do not understand why ClassGraph finds classes from other deployment. How to configure ClassGraph to scan only deployment which ClassGraph itself belongs? I guess that I have to configure class loader, but I do not know how to do it correctly.
Unfortunately it seems that there is no any configuration options that could meet my requirements. Source code modification is needed.
There is JBossClassLoaderHandler#findClasspathOrder method.
First org.jboss.modules.Module is retrieved from class loader. Next getCallerModuleLoader method is invoked and returns different class loader. Original class loader is an instance of org.jboss.modules.ModuleClassLoader class. Class loader retrieved by getCallerModuleLoader method is an instance of org.jboss.as.server.moduleservice.ServiceModuleLoader class. Next moduleMap method is invoked and returns map of modules. This map contains both my deployments. Next operations are executed for each map entry.
I also do not see possibility to add my own implementation of nonapi.io.github.classgraph.classloaderhandler.ClassLoaderHandler without source code modification because handlers are kept in unmodifiable final filed in ClassLoaderHandlerRegistry class.

How to wrap an existing slf4j logger into a kotlin logger?

Given an existing slf4j logger, I would like to wrap it into an kotlin-logging logger.
The classes / methods to do that already exists in the library but are internal, so I can't call them:
mu.internal.KLoggerFactory.wrapJLogger()
Is there another way to do it, which is accessible to users of the library?
It's possible to use the extension method: Logger.toKLogger() since 1.7.6. see this issue for more details: https://github.com/MicroUtils/kotlin-logging/issues/88

Is there a symbolic item to reference spring-cloud config server?

A project I'm working on is utilizing Spring Cloud Config server to handle property update/refresh.
One question that has repeatedly come up is how to reference/serve plain text from the config server.
I know that the server supports serving plain-text. What I'm trying to figure out is that if I have a reference /foo/default/master/logj42.xml.
How would I reference this in an "agnostic" way such that if I were to put:
{configserver}/foo/default/master/log4j2.xml in the config file
The reference {configserver} would be expanded.
Additionally, when using "discovery", if I inject the reference to the "resource" as above, the default mechanism will attempt to use java.net.URLConnection to load the content. I do not think it will resolve the 'discovery' host.
Thanks in advance.
It also can be resolved using Customizing Bootstrap Configuration without aspects by creating custom property source and set configserver uri after locating from discovery.
I had similar issue, more details in this stackoverflow post
I found a way to do this that is minimally invasive but "pierces the veil" of where the config server actually resides.
On the primary application class, the annotation #EnableDiscoveryClient needs to be added.
I created an aspect to add a property source with a key that indicates the actual URI of the server handling the request:
#Component
#Aspect
public class ResolverAspect {
#Autowired
private DiscoveryClient discoveryClient;
#Pointcut("execution(org.springframework.cloud.config.environment.Environment org.springframework.cloud.config.server.environment.EnvironmentController.*(..))
private void environmentControllerResolve();
#Around("environmentControllerResolve()")
public Object environmentControllerResolveServer(final ProceedingJoinPoint pjp) throws Throwable {
final Environment pjpReturn = (Environment)pjp.proceed();
final ServiceInstance localSErviceInstance = discoveryClient.getLocalServiceInstance();
final PropertySource instancePropertySource =
new PropertySource("cloud-instance", Collections.singletonMap("configserver.instance.uri", localServiceInstance.getUri().toString()));
pjpReturn.addFirst(instancePropertySource);
return pjpReturn;
}
}
By doing this, I expose a key configserver.instance.uri which can then be referenced from within a property value and interpolated/resolved on the client.
This has some ramifications with regard to exposing the actual configuration server, but for resolving resources that do not necessarily utilize the discovery client this can be utilized.

Class Redefine not working

SO I am trying to redefine a class. I have a class named folder. In OSGi (using Felix) I have a new Folder class with the same methods but some additional logging.
I am trying to take the Folder Class from Felix and redefine the main Folder class on the main classloader
I do have the agent set on startup.
new ByteBuddy()
.redefine(Class.forName(classToOverride.trim()), ClassFileLocator.ForClassLoader.of(felixClassLoader))
.name(classToOverride.trim())
.make() .load(contextClassLoader);
I have tried different strategies in the load method.
Without any strategies I get the following error
Caused by: java.lang.IllegalStateException: Cannot inject already loaded type: class com.dotmarketing.portlets.folders.model.Folder
at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.inject(ClassInjector.java:187) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:187) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:120) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79) ~[byte-buddy-1.6.12.jar:?]
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4376) ~[byte-buddy-1.6.12.jar:?]
at com.dotmarketing.osgi.GenericBundleActivator.publishBundleServices(GenericBundleActivator.java:177) ~[dotcms_4.1.0_563a5c3.jar:?]
With ClassReloadingStrategy.fromInstalledAgent I get no error but doesn't work.
On a JVM, you cannot simply redefine an already loaded class. You can only redefine a class using a Java agent where Byte Buddy supplies the AgentBuilder API which you can use. Note that it is only possible to change the content of methods but not a class's layout. You probably want to have a look at the Advice API to do so.

FOSRESTBundle: how to alter serializer metadatadirs at controller level

How can I specify a metadata dir for the serializer used by FOSRestBundle, at controller level?
I can't set it up in config.yml because in my case it depends on the request's route.
I've seen in JMSSerializer doc that I could use the following code
$serializer = JMS\Serializer\SerializerBuilder::create()
->addMetadataDir($someDir)
->build();
But how to apply it to an already instanciated serializer (or how to replace it)?
I'm afraid this isn't possible.
Directories are set to metadata drivers when calling build() in SerializerBuilder.php.
Even though you can access the metadata factory used by the Serializer it probably won't help you because the factory has nothing to do with cache directories. Only drivers work with directories.
So the only option for you is probably to create a new instance of Serializer and use that instead of the one from DI.
Edit: Creating a new Serializer works the same way as in your question. Then your DI container should be an instance of Container that has method set() which lets you override any registered service.