spring-projects-experimental / spring-fu Goto Github PK
View Code? Open in Web Editor NEWConfiguration DSLs for Spring Boot
License: Apache License 2.0
Configuration DSLs for Spring Boot
License: Apache License 2.0
The documentation isn't very clear about what a module is, IMHO.
Maybe it's because nothing is published in any repository yet, but it would be helpful to specify that a module is just a Java library, that you just need to add to the compile dependencies (or maybe runtime for some of them) of the project, as you would do with a spring-boot starter, to have access to additional capabilities and additional DSL extensions.
An example gradle/Maven snippet showing how to add the module would help.
Using https://flapdoodle-oss.github.io/de.flapdoodle.embed.mongo/ like in Boot.
How to migrate to such kind of declaring sonfig as fu
offers??
It is non-intuitive (for me)
Say having config
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
private final JHipsterProperties jHipsterProperties;
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
this.jHipsterProperties = jHipsterProperties;
}
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("cip-old-Executor-");
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
and
@Configuration
@EnableJpaRepositories("com.psg.cip.repository")
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
@EnableTransactionManagement
@EnableElasticsearchRepositories("com.psg.cip.repository.search")
public class DatabaseConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
private final Environment env;
private final CacheManager cacheManager;
public DatabaseConfiguration(Environment env, CacheManager cacheManager) {
this.env = env;
this.cacheManager = cacheManager;
}
/**
* Open the TCP port for the H2 database, so it is available remotely.
*
* @return the H2 database TCP server
* @throws SQLException if the server failed to start
*/
@Bean(initMethod = "start", destroyMethod = "stop")
@Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
public Object h2TCPServer() throws SQLException {
try {
// We don't want to include H2 when we are packaging for the "prod" profile and won't
// actually need it, so we have to load / invoke things at runtime through reflection.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> serverClass = Class.forName("org.h2.tools.Server", true, loader);
Method createServer = serverClass.getMethod("createTcpServer", String[].class);
return createServer.invoke(null, new Object[]{new String[]{"-tcp", "-tcpAllowOthers"}});
} catch (ClassNotFoundException | LinkageError e) {
throw new RuntimeException("Failed to load and initialize org.h2.tools.Server", e);
} catch (SecurityException | NoSuchMethodException e) {
throw new RuntimeException("Failed to get method org.h2.tools.Server.createTcpServer()", e);
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new RuntimeException("Failed to invoke org.h2.tools.Server.createTcpServer()", e);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof SQLException) {
throw (SQLException) t;
}
throw new RuntimeException("Unchecked exception in org.h2.tools.Server.createTcpServer()", t);
}
}
@Bean
public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor,
DataSource dataSource, LiquibaseProperties liquibaseProperties) {
// Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env);
liquibase.setDataSource(dataSource);
liquibase.setChangeLog("classpath:config/liquibase/master.xml");
liquibase.setContexts(liquibaseProperties.getContexts());
liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
liquibase.setShouldRun(false);
} else {
liquibase.setShouldRun(liquibaseProperties.isEnabled());
log.debug("Configuring Liquibase");
}
return liquibase;
}
}
how to "translate" this to fu
?
Maybe something on Spring Framework side, or directly typealias Condition = (ApplicationContext) -> Boolean
on Spring Fu side. Conditions should be reused in Spring Fu internals and available to the users as well.
For easy application init for example.
This documentation will be opinionated and in Kotlin.
Jackson is powerful and provides non-blocking parsing support, but also consumes quite a lot of memory on startup. Heap memory after startup is 14 MB without it and 65 MB with (before GC).
Spring MVC has already GSON support but we can't use it since it does not provides non-blocking JSON streaming support.
Maybe we could combine GSON with actson for the non-blocking streaming part in order to build a more lightweight JSON WebFlux codec.
After more thoughts and discussion, it is likely a good idea to leverage Boot infrastructure as much as we can, so this supersedes #5.
Currently, Spring Fu applications are tested mainly in 2 ways:
ApplicationContext
being involved (we need to add examples of that as part of #44).Even if Spring Fu is designed to be testable with not specific support, we should explore if JUnit 5 integration makes sense.
@sbrannen Since Spring Fu is heavily based on ApplicationContextInitializer
, is there something already supported in SpringExtension
we could leverage to register beans on the context and take advantage of test classes @Autowired
support for example?
Spring Fu version of https://spring.io/guides/tutorials/spring-boot-kotlin/
Like Netty and Tomcat ones, based on [JettyHttpServer]https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/http/server/reactive/bootstrap/JettyHttpServer.java).
It will provide org.synchronoss.cloud:nio-multipart-parser
dependency and the related functional configuration.
Like in CoroutineHeadersBuilder
.
Like Netty and Tomcat ones, based on UndertowHttpServer.
This plugin could provide the following functionalities with first-class Gradle Kotlin DSL support for configuration:
val test by tasks.getting(Test::class) { useJUnitPlatform() }
automaticallyUsing infix
to have a SQL like syntax, can be maybe be moved to Spring Data later.
Functional configuration via support in core or in a dedicated module.
This should autoconfigure a WebTestClient
bean when requested based on the server configuration like WebTestClientAutoConfiguration
does.
See Kotlin/kotlinx.coroutines#254. Would be a good fit to expose Flux
cold streams (like for example a Flux<Row>
in R2DBC based SQL persistence an MongoDB Coroutines API.
If we're willing to interoperate w/ configuration annotations then we could change the default ApplicationContext
instance to AnnotationConfigApplicationContext
and hat would allow bean<FooConfig>()
to work out of the box. but that would also require reflection and annotations and other things that frustrate tools like Graal.
If we don't want annotations then we could possibly register modules which then register beans which e arrive at by manually invoking methods in existing java config classes?
Or we could somehow automatically generate functional config from Java configuration classes.
Hi, building fu
fails with
org.opentest4j.AssertionFailedError: expected: </tmp/mylog.txt> but was: <C:\tmp\mylog.txt>
We should be able to do that with something like:
compile("org.springframework:spring-web") {
registerTransform {
from.attribute(filtered, false).attribute(artifactType, "jar")
to.attribute(filtered, true).attribute(artifactType, "jar")
artifactTransform(FilterClasses::class.java)
}
}
}
// Same for spring-webflux, spring-context, spring-data-commons, etc.
class SpringFuWebFilter : ArtifactTransform() {
private val classesToFilter = arrayOf(
"org/springframework/remoting/**",
"org/springframework/web/accept/**",
"org/springframework/web/bind/**",
"org/springframework/web/client/**",
"org/springframework/web/context/**",
"org/springframework/web/filter/**",
"org/springframework/web/jsf/**",
"org/springframework/web/method/**",
"org/springframework/web/multipart/**",
)
)
override fun transform(input: File): List<File> {
return if (...) listOf(input) else emptyList()
}
}
Hi, I've started looking at Spring-fu code, and immediately stumbled upon this. I commend the project developers on deciding to use tabs for indentation, but smart indent for arguments? Is this the recommended formatting for spring-fu? One of the benefits of using tab is customizable indent width without change in the source itself, smart-indent kills this benefit. Look at the part of spring-fu code on the screenshot
https://k62.kn3.net/B/E/A/3/4/7/558.png
2) is with indent settings in IntelliJ set to 4-4-8 (probably what spring-fu original devs have)
application {
logging {
logback = logback {
rollingFileAppender(
file = File.createTempFile("mylog", ".txt"),
name = "MY_ROLLING",
pattern = "%d{yyyy-MM}",
fileNamePattern = "%i.gz",
maxFileSize = "2GB",
maxHistory = 11,
totalSizeCap = "1MB",
append = false
)
}
}
}
instead of
logging {
logback = logback {
rollingFileAppender(
file = File.createTempFile("mylog", ".txt"),
name = "MY_ROLLING",
pattern = "%d{yyyy-MM}",
fileNamePattern = "%i.gz",
maxFileSize = "2GB",
maxHistory = 11,
totalSizeCap = "1MB",
append = false
)
}
}
}
From this I conclude that JetBrains' Kotlin style formatter is not enabled at all. Which is disappointing if it was a conscious decision.
Suggestion: apply kotlin style guide (instructions: https://kotlinlang.org/docs/reference/coding-conventions.html#applying-the-style-guide)
make some fixes (e.g. switch spaces to tabs)
export style settings for contributors and attach them to the project.
The section about immutable data classes is about Kotlin but doesn't actually say anything about Spring Fu. It's not very useful IMHO, and I wondered why it was there when reading the documentation.
Currently even with Graal snapshots it fails with following error:
mx native-image -Dio.netty.noUnsafe=true -H:ReflectionConfigurationFiles=/home/seb/workspace/spring-fu/samples/simple-webapp/graal.json -H:+ReportUnsupportedElementsAtRuntime -Dfile.encoding=UTF-8 -jar /home/seb/workspace/spring-fu/samples/simple-webapp/build/libs/simple-webapp-all.jar
classlist: 10,845.71 ms
(cap): 3,785.48 ms
setup: 7,078.43 ms
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Jun 05, 2018 2:48:49 PM io.netty.util.internal.PlatformDependent <clinit>
INFO: Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system instability.
analysis: 38,365.98 ms
fatal error: java.lang.reflect.MalformedParameterizedTypeException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598)
at java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1005)
at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:381)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:281)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:378)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:104)
Caused by: java.lang.reflect.MalformedParameterizedTypeException
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(ParameterizedTypeImpl.java:58)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:51)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(ParameterizedTypeImpl.java:92)
at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(CoreReflectionFactory.java:105)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:140)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.repository.ClassRepository.getSuperInterfaces(ClassRepository.java:108)
at java.lang.Class.getGenericInterfaces(Class.java:913)
at com.oracle.svm.hosted.analysis.Inflation.fillGenericInfo(Inflation.java:240)
at com.oracle.svm.hosted.analysis.Inflation.checkType(Inflation.java:148)
at java.lang.Iterable.forEach(Iterable.java:75)
at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080)
at com.oracle.svm.hosted.analysis.Inflation.checkObjectGraph(Inflation.java:125)
at com.oracle.graal.pointsto.BigBang.checkObjectGraph(BigBang.java:582)
at com.oracle.graal.pointsto.BigBang.finish(BigBang.java:554)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:642)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:364)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Error: Image building with exit status 1
graal.json
[
{
"name" : "io.netty.channel.socket.nio.NioSocketChannel",
"methods" : [
{ "name" : "<init>", "parameterTypes" : [] }
]
},
{
"name" : "io.netty.channel.socket.nio.NioServerSocketChannel",
"methods" : [
{ "name" : "<init>", "parameterTypes" : [] }
]
}
]
We need to report this kind of issues to Graal project and provide custom spring-fu.json
reflection configuration in order to provide first class support for native images.
Hi,
I would like to know if Spring-fu
is able to serve static websites.
Many thanks in advance.
Cheers
Juan Antonio
We can probably use https://github.com/JetBrains/create-react-kotlin-app or just use Kotlin DOM API as a super jQuery. Minimal JS tooling pain should be required.
Spring Fu modules could leverage Spring Boot starters with a more fine grained logic. We should avoid dependency exclusion for most use case.
kotlin-reflect
is a big 2 MB JAR, Spring Fu should run with https://github.com/Kotlin/kotlinx.reflect.lite which is much much liter. Some updates on Spring Framework side may be needed. We also need to check that Jackson Kotlin support works with it.
By leveraging https://github.com/konrad-kaminski/spring-kotlin-coroutine or providing a dedicated support.
Introduce a functional configuration equivalent for @EnableWebFluxSecurity
.
When available in Spring Data.
Maybe using https://github.com/mockk/mockk.
the doc about the Jackson module mentions:
(and very soon on WebFlux client)
but the webflux module example seems to use it already:
client {
codecs {
jackson()
}
}
So, if it is already available on the client, the Jackson doc should be updated. If it isn't, the webflusx example could add a comment specifying that the jackson codec sn't actually available on the client yet.
Considering the following app :
application {
webflux {
server(netty()) {
routes { GET("/route1", { ok().syncBody("route1") }) }
routes { GET("/route2", { ok().syncBody("route2") }) }
}
}
}
Only the last routes
is available, depending of the order in the DSL.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.