Giter VIP home page Giter VIP logo

spring-projects-experimental / spring-boot-migrator Goto Github PK

View Code? Open in Web Editor NEW
426.0 15.0 87.0 88.97 MB

Spring Boot Migrator (SBM) is a tool for automated code migrations to upgrade or migrate to Spring Boot

License: Apache License 2.0

Java 98.36% HTML 0.89% CSS 0.14% JavaScript 0.06% RAML 0.01% Less 0.22% XSLT 0.02% FreeMarker 0.17% Dockerfile 0.01% Shell 0.13%
spring-boot automation tool cli migration-tool

spring-boot-migrator's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-boot-migrator's Issues

MIgrate all properties to @Stateless when migrating ejb-jar.xml to annotation

What needs to be done

All possible attributes for stateless session bean declarations given in an EJB deployment descriptor (ejb-jar.xml) must be migrated to annotations when migrate-ejb-jar-deployment-descriptor is applied.

Why it needs to be done

Currently, only beanName attribute is migrated.
If an ejb-jar.xml contains additional attributes these are not migrated and the migration is broken/incomplete.

Additional Information

See MigrateEjbDeploymentDescriptor.handleStatelessSessionBean()

Generate Test stub for HTTP integration tests

What needs to be done

A Spring integration test should be created for HTTP endpoints found in the scanned application.
The solution should be generic enough to generate tests not only for Spring Controller but also for e.g. Mule HTTP components.

Why it needs to be done

Acceptance Criteria

/info panel
Given precondition
When action
Then result

Additional Information

Refactor ScanShellCommand and ScanCommand

What needs to be done

Rework the flow of scanning, precondition check, and parsing in ScanShellCommand.
The project should be scanned only once.

Why it needs to be done

Currently, the given project is scanned twice. Once for the precondition check and again inside ScanCommand.

Provide BuildFile.hasDependencyMatchingRegex(...)

What needs to be done

Provide method buildFile.hasDependencyMatchingRegex() which considers transitive dependencies too as counterpart to buildFile.hasDeclaredDependencyMatchingRegex()

Acceptance Criteria

hasDependencyMatchingRegex

Given pom.xml contains a dependency that brings a transitive dependency
When hasDependencyMatchingRegex(<regex for the transitive dependency>) is called on this BuildFile
Then this method should return true

Given pom.xml contains a dependency that brings a transitive dependency
When hasDependencyMatchingRegex(<regex for the declared dependency>) is called on this BuildFile
Then this method should return true

hasDeclaredDependencyMatchingRegex

Given pom.xml contains a dependency that brings a transitive dependency
When hasDeclaredDependencyMatchingRegex(<regex for the transitive dependency>) is called on this BuildFile
Then this method should return false

Given pom.xml contains a dependency that brings a transitive dependency
When hasDeclaredDependencyMatchingRegex(<regex for the declared dependency>) is called on this BuildFile
Then this method should return true

Additional Information

See MigrateWlsEjbDeploymentDescriptor.incorporateIntoSourceFile():69

Replace custom Resource with Spring Resource

What needs to be done

Replace all usages of org.springframework.sbm.project.parser.Resource with org.springframework.core.io.Resource.
Remove mapping and declaration of org.springframework.sbm.project.parser.Resource

Why it needs to be done

The MavenProjectParser uses a custom Resource implementation.
In ProjectContextInitializer the custom Resource gets mapped to a Spring Resource.
This is a relict and can be removed so only Spring Resource is used.

Mule: Add ability to access headers during transformation

labels: ["in: mule-3.9"]

What needs to be done

Currently, DWL transformations are translated as below

Sample input
        <dw:transform-message doc:name="Transform Message">
            <dw:set-payload><![CDATA[%dw 1.0
%output application/java
---
(flowVars.someVar splitBy ",") map ("'" ++ $ ++ "'") joinBy ","]]></dw:set-payload>
        </dw:transform-message>
Generates following translation/output:
 @Bean
    IntegrationFlow transform() {

        return IntegrationFlows.from(...)
                ... 
               .transform(TransformClass::transform)
                ...
                .get();
    }
class TransformClass {
    /** contents of DWL transformation will be pasted as comments*/
    public static TransformClass transform(Object payload) {
    }
}

If you look at the above TransformClass there is only access to payload not headers

We need provision to access both headers and payload whilst transformation.

Why it needs to be done

In mule transformations, there will be instances where we need to access headers and payload whilst performing translations. This is evident from client applications that we have encountered where this pattern is used prolifically.

Additional Information

Possible solution can be found here.

Migrate simple local stateless EJB 2.1 to Spring Boot

Depends-on #62

What needs to be done

Provide a recipe to migrate a simple EJB 2.1 to Spring Boot.

Why it needs to be done

Acceptance Criteria

Given

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_1" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1">
   <description>Example of a session bean</description>
   <display-name>MyTimeBeanEJBName</display-name>
   <enterprise-beans>
      <session id="Session_MyTime">
         <description>An EJB named MyTimeBean</description>
         <display-name>MyTimeBeanName</display-name>
         <ejb-name>TheTimeBean</ejb-name>
         <local-home>mytimepak.MyTimeLocalHome</local-home>
         <local>mytimepak.MyTimeLocal</local>
         <ejb-class>mytimepak.MyTimeBean</ejb-class>
         <session-type>Stateless</session-type>
         <transaction-type>Container</transaction-type>
      </session>
   </enterprise-beans>
</ejb-jar>
package mytimepak;
public class MyTimeBean implements javax.ejb.SessionBean {

	public void ejbCreate() {}
	public void ejbActivate() {}
   	public void ejbPassivate() {}
   	public void setSessionContext(javax.ejb.SessionContext ctx) {}
   	public void unsetSessionContext() {}
   	public void ejbRemove() {}

	public String getTime() {
		String s = new java.util.Date().toString();
		return s;
	}
}

Expected

package mytimepak;

import ...springframework..Service;
import ...springframework..Transactional;

/**
* An EJB named MyTimeBean
*/
@Service("TheTimeBean")
@Transactional
public class MyTimeBean {

	public String getTime() {
		String s = new java.util.Date().toString();
		return s;
	}
}

Additional Information

Fix Conditions for Spring Boot 2.4 to 2.5 Upgrade recipes

Thanks for reporting @Turbots!

Describe the bug
Some recipes of the Spring Boot 2.4 to 2.5 Upgrade functionality are always shown as applicable.

To Reproduce

  1. Run the demo-upgrade-spring-boot-report demo and upgrade the demo app to 2.5.x
  2. Then scan the application again
  3. The applied recipes for 2.4.x Spring Boot is still shown as applicable

Expected behavior
The 2.4 upgrade-related recipes should not be shown for any Spring Boot application with a version different from 2.4.x.

Additional context
For multiple of these recipes the condition is set to org.springframework.sbm.common.migration.conditions.TrueCondition which makes SBM always show it as applicable.

Make Maven Artifact cache configurable

What needs to be done

Make Maven artifact cache configurable by setting an application property.

Read from Maven Repository but download new dependencies to separate Maven cache (current)

new MavenArtifactDownloader(
                        ReadOnlyLocalMavenArtifactCache.mavenLocal().orElse(
                            new LocalMavenArtifactCache(Paths.get(System.getProperty("user.home"), ".rewrite", "cache", "artifacts")

Use local Maven repository for reading and writing

new MavenArtifactDownloader(new LocalMavenArtifactCache(Paths.get(System.getProperty("user.home"), ".m2", "repository")), ...

Why it needs to be done

It can be useful (and easier to understand) if all dependencies are stored and retrieved from the local Maven repository but then SBM potentially overwrites dependencies in the local Maven repository.
Allow a user to choose.

Additional Information

See DependencyHelper.downloadArtifacts(...) for artifact configuration and ApplicationProperties for properties

Verify SBM works with Windows

What needs to be done

Verify SBM works with Windows.

  • Support project path provided as Windows Path, e.g. C:\my-project\dir
  • Fix exclude pattern (sbm.ignoredPathsPatterns)
  • Verify build with Windows
  • Fix emojis in console
  • Fix formatting in console

Why it needs to be done

When using SBM under windows it complains about the exclude pattern **/.git/**.
Providing .git as pattern on startup succeeded.

Add support for <db:select /> in mule

What needs to be done

Add support for <db:select />

Acceptance Criteria

/info panel
Given
Mule xmls are detected
When
<db:select /> component is used
Then
Translate it to Equivalent Spring Integration DSL

Example:
Detects:

<db:select config-ref="Oracle_Configuration" doc:name="Database" fetchSize="500" maxRows="500">
            <db:dynamic-query><![CDATA[SELECT * from students]]></db:dynamic-query>
        </db:select>

DSL Translation:

.handle((p, h) -> jdbcTemplate.queryForList("SELECT * from students limit 500"))

Additional Information

Change properties in DataSourceInitializerConfiguration

If boot-2.4-2.5-sql-init-properties gets applied after boot-2.4-2.5-datasource-initializer the properties used in the DataSourceInitializerConfiguration (spring.datasource.schema-...) get changed. This is wrong.

To avoid this probably easiest is to change property names in DataSourceInitializerConfiguration, e.g. to spring.sql.init.schema-username and -password respectively.

Originally posted by @fabapp2 in #133 (comment)

Imported inner classes not always used

Describe the bug
When migrating from JAX-RS to Spring inner class HttpStatus.Series is imported but not used everywhere.
Series custom = HttpStatus.Series.resolve(code); could be Series custom = Series.resolve(code); instead.

To Reproduce
Steps to reproduce the behavior:

  1. Replace HttpStatus.Series with Series in expected code of ResponseStatusFamilyTest.enumConstantsTest()
  2. Run test

Expected behavior
Inner classes are used when imported

Recipe: Migrate from SpringFox to SpringDoc

What needs to be done

Provide a recipe to convert an application from using SpringFox to using SpringDoc.

Why it needs to be done

SpringFox is an often used library to document Spring API's, that has not kept up with recent Spring releases. That prevents users from upgrading their Spring Boot applications.

SpringDoc is an alternative or even successor, which has nicely documented the steps to take for a partial migration.

Acceptance Criteria

/info panel
Given an application using springfox
When the springfox-to-springdoc recipe is applied
Then the application uses springdoc

Better error handling when a newly added class couldn't be compiled

What needs to be done

Provide better handling in JavaSourceSetImpl when adding a JavaSource which doesn't compile.

List<J.CompilationUnit> compilationUnits = javaParser.parse(sourceCode);
        J.CompilationUnit parsedCompilationUnit = compilationUnits.get(0);

Verify that compilationUnits is not empty/null

Why it needs to be done

The error message when compilationUnits is empty, because compilation failed)
image

Acceptance Criteria

/info panel
Given a user adds a new Java source file through JavaSourceSetImpl
When the source code doesn't compile and the list of compilation units is empty
Then the stacktrace should provide more precise information about what went wrong

Additional Information

Add precondition check when scanning

What needs to be done

A set of preconditions should be run at the beginning of a scan to warn the user about
potential problems when scanning an application that does not fulfill requirements.

Why it needs to be done

For a better UX a user should be warned about expected problems when scanning (but before applying recipes) an application that does not fulfill given preconditions.

Acceptance Criteria

Given A user scans an application that does not fulfill one or more preconditions +
When SBM performs a precondition check that fails +
Then A warning is shown to the user and the scan is cancelled.

Precondition Warning
No pom.xml found SBM requires a Maven build file. Please provide a minimal pom.xml.
no dir src/main/java exists Precondition check could not find a src/main/java dir. This dir is required.
Git-Support is enabled but no .git exists Git-Support is enabled but the scanned project is not under git.
Multiple modules found Maven reactor support is experimental and not fully supported.

Additional Information

Failure to scan a project with empty properties in the pom.xml

Thanks @virgium03 for raising this issue!

Version: 0.9.1.

If any of the pom.xml files in a project contain empty properties elements, the tool fails. The fix is to remove the empty properties element from the incriminated pom.xml file.

Examples which generate a failure:

<properties> </properties>

or

<properties>
 
</properties>

The stacktrace is as follows:

java.io.UncheckedIOException: Failed to parse C:\Users\ratoico\work\projects\uumds-admin\admin-common\common-facade\pom.xml
at org.openrewrite.maven.internal.RawMaven.parse(RawMaven.java:90)
at org.openrewrite.maven.MavenParser.lambda$parseInputs$0(MavenParser.java:74)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.openrewrite.maven.MavenParser.parseInputs(MavenParser.java:75)
at com.vmware.sbm.project.buildfile.RewriteMavenParser.parseInputs(RewriteMavenParser.java:46)
at org.openrewrite.Parser.parse(Parser.java:39)
at com.vmware.sbm.project.buildfile.OpenRewriteMavenBuildFilesFactory.applyProjections(OpenRewriteMavenBuildFilesFactory.java:32)
at com.vmware.sbm.project.SimpleProjectContextBuilder.buildContext(SimpleProjectContextBuilder.java:43)
at com.vmware.sbm.project.CachingProjectContextBuilder.buildContext(CachingProjectContextBuilder.java:43)
at com.vmware.sbm.commands.ScanCommand.execute(ScanCommand.java:26)
at com.vmware.sbm.shell.ScanShellCommand.scan(ScanShellCommand.java:39)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
at org.springframework.shell.Shell.evaluate(Shell.java:180)
at org.springframework.shell.Shell.run(Shell.java:142)
at org.springframework.shell.jline.InteractiveShellApplicationRunner.run(InteractiveShellApplicationRunner.java:84)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:787)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1313)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
at com.vmware.sbm.SpringShellApplication.main(SpringShellApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") to element of java.util.LinkedHashMap<java.lang.String,java.lang.String> (but could if coercion was enabled using CoercionConfig)
at [Source: (sun.nio.ch.ChannelInputStream); line: 17, column: 5] (through reference chain: org.openrewrite.maven.internal.RawPom["properties"])
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadCoercion(DeserializationContext.java:1666)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._checkCoercionFail(StdDeserializer.java:1432)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromEmptyString(StdDeserializer.java:325)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromString(StdDeserializer.java:276)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:444)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:32)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:565)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:449)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1405)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3585)
at org.openrewrite.maven.internal.RawMaven.parse(RawMaven.java:84)
... 38 more

Upgrade to OpenRewrite 7.20.0

  • Fix MavenProjectParser, see https://github.com/openrewrite/rewrite-maven-plugin/blob/main/src/main/java/org/openrewrite/maven/MavenMojoProjectParser.java and code provided
  • Rework adding resources and java classes, JavaParser creates the JavaSourceSet now

Remove call to build() when migrating JAX-RS Response to ResponseEntity

Describe the bug
When migrating JAX-RS to Spring @RestController calls to Response are replaced with calls to ResponseEntity and the build() call is kept. This method is not defined in ResponseEntity and must be replaced.

To Reproduce
Steps to reproduce the behavior:

  1. Remove the .build() in expected output of ResponseEntityReplacementTest.testReplaceOkWithBody()
  2. See error

Expected behavior
The migrated Spring code has no call to ResponseEntity.build()

Additional context
More occurrences marked with // FIXME: #115

Provide a way to toggle the sbm.gitSupportEnabled flag in Shell

labels: ["good first issue","in: JEE","to_archive"]

What needs to be done

The shell should allow the user to toggle the sbm.gitSupportEnabled flag.

Why it needs to be done

When trying SBM it can be annoying to scan projects not under git as the precondition check will complain that the flag is true but the application is not under git.
This would allow a user to just turn git support off without leaving the Shell.

Acceptance Criteria

Given sbm.gitSupportEnabled is true
When calling set-property sbm.gitSupportEnabled false in shell
Then get-property sbm.gitSupportEnabled should return false

Given sbm.gitSupportEnabled is false
When calling set-property sbm.gitSupportEnabled true in shell
Then get-property sbm.gitSupportEnabled should return true

Support Mule integration tests on Mac M1

What needs to be done

Currently, the integration test BootifySimpleMuleAppIntegrationTest uses ibmcom/mq which does not support ARM architecture. To mediate this the integration test is ignored on Mac M1 (ARM) for now.

Why it needs to be done

The integration test should run on all architectures.

Additional Information

The dockerhub repo says the image is not maintained anymore and images should be retrieved from IBM image repo.
See https://hub.docker.com/r/ibmcom/mq.

Failure to run because of a Maven dependency with the optional value inherited from a parent pom

Thanks @virgium03 for raising this issue!

Version: 0.9.1

Have a multi-module Maven project like this, where project B inherits from the project A pom.xml file:

A
├── pom.xml
├── B
├── pom.xml

If project B (child) has a Maven dependency defined like this:

<dependency>
  <groupId>a.b.c</groupId>
  <artifactId>xyz</artifactId>
  <version>1.0</version>
  <optional>${boolean-variable}</optional>
</dependency>

and project A (parent) has the boolean.variable defined as a property like so:

<properties>
  <boolean-variable>true</boolean-variable>
</properties>

the scanning fails like this:

java.io.UncheckedIOException: Failed to parse ${project.path}\pom.xml
at org.openrewrite.maven.internal.RawMaven.parse(RawMaven.java:90)
at org.openrewrite.maven.MavenParser.lambda$parseInputs$0(MavenParser.java:74)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.openrewrite.maven.MavenParser.parseInputs(MavenParser.java:75)
at com.vmware.sbm.project.buildfile.RewriteMavenParser.parseInputs(RewriteMavenParser.java:46)
at org.openrewrite.Parser.parse(Parser.java:39)
at com.vmware.sbm.project.buildfile.OpenRewriteMavenBuildFilesFactory.applyProjections(OpenRewriteMavenBuildFilesFactory.java:32)
at com.vmware.sbm.project.SimpleProjectContextBuilder.buildContext(SimpleProjectContextBuilder.java:43)
at com.vmware.sbm.project.CachingProjectContextBuilder.buildContext(CachingProjectContextBuilder.java:43)
at com.vmware.sbm.commands.ScanCommand.execute(ScanCommand.java:26)
at com.vmware.sbm.shell.ScanShellCommand.scan(ScanShellCommand.java:39)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
at org.springframework.shell.Shell.evaluate(Shell.java:180)
at org.springframework.shell.Shell.run(Shell.java:142)
at org.springframework.shell.jline.InteractiveShellApplicationRunner.run(InteractiveShellApplicationRunner.java:84)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:787)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1313)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
at com.vmware.sbm.SpringShellApplication.main(SpringShellApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.lang.Boolean from String "${boolean-variable}": only "true" or "false" recognized
at [Source: (sun.nio.ch.ChannelInputStream); line: 247, column: 44] (through reference chain: org.openrewrite.maven.internal.RawPom["dependencies"]->org.openrewrite.maven.internal.RawPom$Dependencies["dependency"]->java.util.ArrayList[33]->org.openrewrite.maven.internal.RawPom$Dependency["optional"])
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1851)
at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:1079)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseBoolean(StdDeserializer.java:552)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$BooleanDeserializer.deserialize(NumberDeserializers.java:227)
at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$BooleanDeserializer.deserialize(NumberDeserializers.java:200)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:565)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:449)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1405)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:347)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:565)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:449)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1405)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)
at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:114)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:565)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:449)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1405)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:362)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:195)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3585)
at org.openrewrite.maven.internal.RawMaven.parse(RawMaven.java:

Ignore all resources in .gitignore when scanning

What needs to be done

Contents of .gitignore should be ignored when scanning a given application with PathScanner.

Why it needs to be done

Some resources and dirs (like target) are ignored by default, this can be configured by setting sbm.ignoredPathsPatterns. But all ignored resources in .gitignore should also be ignored.

Acceptance Criteria

Given the project to migrate contains a resource some-file.txt
When the .gitgnore contains some-file.txt
Then PathScanner.scan(Path) should not return the ignored resource(s)

It must handle all kinds of ignore patterns from .gitignore.

Additional Information

See sbm.ignoredPathsPatterns in components/sbm-core/src/main/resources/application-core.properties
See PathScanner

Integrate logback logging into JLine/Shell

What needs to be done

Log messages on info/warn/error level should be routed to the shell output with a similar (no) formatting as other printouts in the shell.

Why it needs to be done

Log statements printed by default Console logback adapter look very different from the output printed by RecipeProgressRenderer.
To make log statements look like other printouts the log messages should be retrieved by a custom Appender and the default console appender needs to be deactivated.

Acceptance Criteria

Given During a running Action
When log.info(...) gets called
Then the message should be printed to the user as [ok] <message>

Given During a running Action
When log.warn(...) gets called
Then the message should be printed to the user as [!] <message> with [!] in yellow/orange

Given During a running Action
When log.error(...) gets called
Then the message should be printed to the user as [X] <message> with [X] in red

Additional Information

The first (maybe naive) attempt worked for loggers retrieved through a call to LoggerFactory but failed with logger retrieved using lombok's @Slf4J annotation.

The re-routing of Logback log messages fails in unit test (RecipeProgressRendererTest) when ran in combination with other integration tests. Guessing that the combination with lombok @slf4j is the issue. Commented out the code that starts the re-routing.

Keep information that was not migrated when migrating EJB definitions from ejb-jar.xml

What needs to be done

Before removing an EJB definition section from ejb-jar.xml it must be verified that all information was migrated. Currently, the EJB definition is removed right away.
Remove or comment out all migrated properties and only remove the EJB definition if no properties exist.

Why it needs to be done

As long as not everything is guaranteed to be migrated from an ejb-jar.xml deployment descriptor it must be verified that all existing information has been migrated before removing the information.
Otherwise, information might be lost and the migration would be incomplete/broken.

Acceptance Criteria

Given migrate-ejb-jar-deployment-descriptor is applied
When ejb-jar.xml contains handled and unhandled elements
Then the user must understand what has been automatically migrated and what needs to be migrated manually

Additional Information

See MigrateEjbDeploymentDescriptor:41 (Action)
See MigrateEjbJarDeploymentDescriptorRecipe (Recipe)

Multiple Dataweave transform message in same flow should produce multiple transform class

Describe the bug
A flow with a Dataweave transformation will result in creation of a transformation class whose name is dependent on flow name.
When a flow contains multiple dataweave transformation, it should produce multiple classes, right now it is producing only one class for multiple dataweave transformations.

To Reproduce
Steps to reproduce the behavior:

  1. Setup a java template project example here
  2. create a new file in resources folder called multipletransform.xml
  3. paste the below content for multipletransform.xml
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:dw="http://www.mulesoft.org/schema/mule/ee/dw" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd
http://www.mulesoft.org/schema/mule/ee/dw http://www.mulesoft.org/schema/mule/ee/dw/current/dw.xsd">
    <flow name="multipleTransforms">
        <dw:transform-message doc:name="Transform Message">
            <dw:set-payload><![CDATA[%dw 1.0
%output application/json indent = true, skipNullOn = "everywhere"
---
{
	"hello": {
		"world": {
			"hello": "indeed!",
		},
	}
}]]></dw:set-payload>
        </dw:transform-message>
        <logger />
        <dw:transform-message doc:name="Build Response Message">
            <dw:set-payload><![CDATA[%dw 1.0
%output application/json indent = true, skipNullOn = "everywhere"
---
{
	"responseBody": {
		"responseInfo": {
			"responseStatus": "200"
		},
	}
}]]></dw:set-payload>
        </dw:transform-message>
    </flow>
</mule>

  1. Run spring boot migrator and apply mule-to-boot recipe.
  2. You will see only one transform file called MultipleTransformsTransform

Expected behavior
Since there are two DWL transforms, this should produce two distinct transform files, may be MultipleTransformsTransform_1 and MultipleTransformsTransform_2

Screenshots
image

Add support for classes annotated with @WebListener

What needs to be done

HTTP Listener annotated with @WebListener should be handled by migrate-annotated-servlets recipe.
While looking at the code this should be the case already (the annotation has package javax.servlet.*.
Implement a new / extend an existing test to verify that event listener annotated with @WebListener are available in the migrated Spring Boot application.

Why it needs to be done

@WebListener works similar to @WebServlet but it's not tested (and might require enhancing of the recipe).

Acceptance Criteria

Given A JEE application has a event listener annotated with @WebListener
When migrate-annotated-servlets is applied
Then The migrated Spring Application must recognize and initialize the WebListener

Additional Information

Add/Look into Dependabot support

Would adding a tool like Dependabot or Renovate be an option for this project? That could eliminate the need to explicitly upgrade dependencies by hand.. Looking through the list both of these properties are outdated:

  <openrewrite.version>7.16.3</openrewrite.version>
  <openrewrite.spring.version>4.14.1</openrewrite.spring.version>

The most recent versions as of writing are:

  <openrewrite.version>7.19.0</openrewrite.version>
  <openrewrite.spring.version>4.17.0</openrewrite.spring.version>

Originally posted by @timtebeek in #7 (comment)

Unmarshal EJB 2.1 ejb-jar.xml deployment descriptor

What needs to be done

EjbJarXml specialized resource should unmarshal ejb-jar.xml deployment descriptor for EJB 2.1.

Why it needs to be done

Acceptance Criteria

Given The scanned application contains this ejb-jar.xml deployment descriptor

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
   http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_2_1.xsd" version="2.1">
   <description>Example of a session bean</description>
   <display-name>MyTimeBeanEJBName</display-name>
   <enterprise-beans>
      <session id="Session_MyTime">
         <description>An EJB named MyTimeBean</description>
         <display-name>MyTimeBeanName</display-name>
         <ejb-name>MyTimeBean</ejb-name>
         <local-home>mytimepak.MyTimeLocalHome</local-home>
         <local>mytimepak.MyTimeLocal</local>
         <ejb-class>mytimepak.MyTimeBean</ejb-class>
         <session-type>Stateless</session-type>
         <transaction-type>Container</transaction-type>
      </session>
   </enterprise-beans>
</ejb-jar>

When projectContext.search(new EjbJarXmlResourceFilter()).get().getEjbJarXml() is called
Then The XML data (e.g. ejb-name) shozdl be accessible through the EjbJarXml API

Additional Information

Support mule component <foreach />

What needs to be done

When component is detected, translate it to appropriate spring DSL translation

Example inputs and outputs

Sample 1

input

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:dw="http://www.mulesoft.org/schema/mule/ee/dw"
	xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
	xmlns:spring="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/ee/dw http://www.mulesoft.org/schema/mule/ee/dw/current/dw.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
	<flow name="foreach">
		<http:listener config-ref="HTTP_Listener_Configuration" path="/foreach" doc:name="HTTP"/>	
        <foreach collection="#[['apple', 'banana', 'orange']]">
        	<logger message="#[payload]" level="INFO" />
        </foreach>
		<logger message="Done with for looping" level="INFO" />
	</flow>
</mule>

output:

    @Bean
    IntegrationFlow flow() {
        return IntegrationFlows.from(Http.inboundGateway("/foreachtest"))
                //TODO: translate expression #[['apple', 'banana', 'orange']] which must produces an array
                // to iterate over
                .split()
                .log()
                .aggregate()
                .log()
                .get();
    }
Sample 2

Children of foreach can be complex such as choice

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:dw="http://www.mulesoft.org/schema/mule/ee/dw"
	xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
	xmlns:spring="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/ee/dw http://www.mulesoft.org/schema/mule/ee/dw/current/dw.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
	<flow name="foreach">
		<http:listener config-ref="HTTP_Listener_Configuration" path="/foreach" doc:name="HTTP"/>	
        <foreach collection="#[[1, 2, 3, 4]]">
        	<logger message="#[payload]" level="INFO" />
        	<choice doc:name="Choice">
			<when expression="#[payload == 1]">
				<logger level="INFO" message="Ondu"></logger>
			</when>
			<when expression="#[payload == 2]">
				<logger level="INFO" message="Eradu"></logger>
			</when>
			<when expression="#[payload == 3]">
				<logger level="INFO" message="Mooru"></logger>
			</when>
			<otherwise>
				<logger level="INFO" message="Moorina mele"></logger>
			</otherwise>
		</choice>
        </foreach>
		<logger message="Done with for looping" level="INFO" />
	</flow>
</mule>

output

@Bean
    IntegrationFlow foreach() {
        return IntegrationFlows.from(Http.inboundChannelAdapter("/foreach")).handle((p, h) -> p)
                //TODO: translate expression #[[1, 2, 3, 4]] which must produces an array
                // to iterate over
                .split()
                /* TODO: LinkedMultiValueMap might not be apt, substitute with right input type*/
                .<LinkedMultiValueMap<String, String>, String>route(
                        p -> p.getFirst("dataKey") /*TODO: use apt condition*/,
                        m -> m
                                .subFlowMapping("dataValue" /*TODO: Translate dataValue to #[payload == 1]*/,
                                        sf -> sf.log(LoggingHandler.Level.INFO, "Ondu")
                                )
                                .subFlowMapping("dataValue" /*TODO: Translate dataValue to #[payload == 2]*/,
                                        sf -> sf.log(LoggingHandler.Level.INFO, "Eradu")
                                )
                                .subFlowMapping("dataValue" /*TODO: Translate dataValue to #[payload == 3]*/,
                                        sf -> sf.log(LoggingHandler.Level.INFO, "Mooru")
                                )
                                .resolutionRequired(false)
                                .defaultSubFlowMapping(sf -> sf.log(LoggingHandler.Level.INFO, "Moorina mele"))
                )
                .aggregate()
                .log(LoggingHandler.Level.INFO, "Done with for looping")
                .get();
    }

More information of foreach mule component can be found here

Additional notes

Batch sizing using foreach can be supported later

Fix MoveFilesActionTest in CI

Depends-on: #52

What needs to be done

Investigate, fix and/or close.
See comments // TODO: #486

Old Issue

MoveFilesActionTest started failing in CI while passing locally.
The file AnotherFile.foo was moved successfully while the new path for SomeFile.foo resolved to the path without the filename.

  • Fix test
  • Add assertion again (commented out)
  • Remove debug printouts in test

Fix calculation of base package

What needs to be done

Calculating base packages should return the common parent package, even if it is the default (no) package.
In BasePackageCalculator.calculateBasePackage(List<JavaSource> javaSources)

Why it needs to be done

For e.g. two classes com.acme.some.A and com.acme.other.B the current calculation does fail as it does not recognize com.acme as possible common base package.

Acceptance Criteria

Given base package should be calculated for an application
When two classes com.acme.some.A and com.acme.other.B exist
Then the returned base package should be com.acme

Given base package should be calculated for an application
When two classes com.acme.some.A and com.example.other.B exist
Then the returned base package should be com

Given base package should be calculated for an application
When two classes com.acme.some.A and org.example.other.B exist
Then the returned base package should be ""

See JavaSourceSetImplTest.getBasePackageShouldReturnDefaultIfNoDistinctRootPackageExists()
This test should expect com.vmware.sbm instead of the default base package.

Additional Information

All recipes/actions calculating the base package for Spring components and configurations should check if the returned base package is the default package/empty and handle this situation. At least initialize-spring-boot-migration would be affected.
For Spring applications to work without one common base package, a @ComponentScan could be used.

Support for Nested <choice> element

labels: ["type: enhancement","in: mule-3.9"]

What needs to be done

When a choice element is embedded inside another choice element we need to translate appropriate spring DSL.

Why it needs to be done

Choice inside a choice is supported by mule, to complete component support we need to do this.

Example of nested choice

        <choice doc:name="Choice">
            <when expression="#[flowVars.language == 'Spanish']">
                <choice>
                    <when expression="#[flowVars.sayHello == 'true']">
                        <set-payload value="Hola!"/>
                    </when>
                    <otherwise>
                        <set-payload value="Adiós"/>
                    </otherwise>
                </choice>
            </when>
            <when expression="#[flowVars.language == 'French']">
                <choice>
                    <when expression="#[flowVars.sayHello == 'true']">
                        <set-payload doc:name="Reply in French" value="Bonjour!"/>
                    </when>
                    <otherwise>
                        <set-payload doc:name="Reply in French" value="Au revoir"/>
                    </otherwise>
                </choice>
            </when>
            <otherwise>
                <set-variable variableName="language" value="English" doc:name="Set Language to English"/>
                <set-payload doc:name="Reply in English" value="Hello"/>
            </otherwise>
        </choice>

DSL equivalent

To be written.

Additional information

There is already support for Non nested Choice component. One can find the source here and tests here

Integration tests using Docker fail with Mac M1 (ARM)

Describe the bug
Integration tests that use a Docker container fail with Mac M1

To Reproduce
Steps to reproduce the behavior:

  1. Run BootifyAnnotatedServletsIntegrationTest
  2. See error

Expected behavior
The application builds a Docker container and runs it using testcontainers

Stacktrace
missing compatible architecture (have 'i386,x86_64', need 'arm64e')

12:41:53.485 [main] ERROR o.t.d.DockerClientProviderStrategy -     UnixSocketClientProviderStrategy: failed with exception RuntimeException (java.lang.UnsatisfiedLinkError: /private/var/folders/sh/nw78y14d38jb_57ptd_k0jdr0000gq/T/jna-1226527383/jna14683793770511009461.tmp: dlopen(/private/var/folders/sh/nw78y14d38jb_57ptd_k0jdr0000gq/T/jna-1226527383/jna14683793770511009461.tmp, 0x0001): tried: '/private/var/folders/sh/nw78y14d38jb_57ptd_k0jdr0000gq/T/jna-1226527383/jna14683793770511009461.tmp' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e'))). Root cause UnsatisfiedLinkError (/private/var/folders/sh/nw78y14d38jb_57ptd_k0jdr0000gq/T/jna-1226527383/jna14683793770511009461.tmp: dlopen(/private/var/folders/sh/nw78y14d38jb_57ptd_k0jdr0000gq/T/jna-1226527383/jna14683793770511009461.tmp, 0x0001): tried: '/private/var/folders/sh/nw78y14d38jb_57ptd_k0jdr0000gq/T/jna-1226527383/jna14683793770511009461.tmp' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e')))

Environment (please complete the following information):

  • OS: Mac OSX on ARM/M1
  • JDK 11
openjdk version "11.0.14.1" 2022-02-08 LTS
OpenJDK Runtime Environment Zulu11.54+25-CA (build 11.0.14.1+1-LTS)
OpenJDK 64-Bit Server VM Zulu11.54+25-CA (build 11.0.14.1+1-LTS, mixed mode)

Additional context

  • Dependency to net.java.dev.jna:jna < 5.8.0 was brought in by spring-shell-starter and has been excluded.
  • Docker container created during test starts when using Docker docker run -it docker.io/library/jboss-sample:1.0.0, but with a warning
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

Autocomplete both applications to scan, and recipes to apply

What needs to be done

Spring Shell can support auto completion through a ValueProvider interface.
I image you'd need two separate implementation, each for the respective purpose.

Why it needs to be done

Nice usability improvement.

Acceptance Criteria

Given the interactive prompt
When the user types scan (or apply)
And the user presses TAB
Then auto complete suggestions appear

Add support for classes annotated with @WebFilter

What needs to be done

HTTP Listener annotated with @WebFilter should be handled by migrate-annotated-servlets recipe.
While looking at the code this should be the case already (the annotation has package javax.servlet.*.
Implement a new / extend an existing test to verify that web filters annotated with @WebFilter are available in the migrated Spring Boot application.

Why it needs to be done

@WebFilter works similar to @WebServlet but it's not tested (and might require enhancing of the recipe).

Acceptance Criteria

Given A JEE application has a event listener annotated with @WebFilter
When migrate-annotated-servlets is applied
Then The migrated Spring Application must recognize and initialize the WebFilter

Additional Information

recipesFound null in upgrade-asciidoc.ftl:46 breaks HTML report generation

Describe the bug
Template error generating HTML report.

freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> recipesFound  [in template "upgrade-asciidoc.ftl" at line 46, column 6]

To Reproduce
Steps to reproduce the behavior:

  1. checkout spring petclinic on spring boot 2.4
#!/bin/bash
set -e
source "$HOME/.sdkman/bin/sdkman-init.sh"

project='spring-petclinic-sbm'

wget --no-clobber https://github.com/spring-projects-experimental/spring-boot-migrator/releases/download/0.11.0/spring-boot-migrator.jar

git clone [email protected]:spring-projects/spring-petclinic.git $project
cd $project
#git reset --hard
#git clean -f
git checkout 09e07869ac8cea1d08bd62802d5e0dad97827b87 # commit on 2.4.x
cd -

sdk use java 11.0.15-tem
java -jar spring-boot-migrator.jar
  1. scan spring-petclinic-sbm
  2. apply boot-2.4-2.5-dependency-version-update
  3. apply boot-2.4-2.5-sql-init-properties
  4. apply boot-2.4-2.5-upgrade-report

Expected behavior
A HTML report, possibly with all steps resolved

Stacktrace

spring-petclinic-sbm:> apply boot-2.4-2.5-upgrade-report
Applying recipe 'boot-2.4-2.5-upgrade-report'
..   Create Upgrade Report for a Spring Boot 2.4 Application16:42:24.213 [main] ERROR freemarker.runtime - Error executing FreeMarker template
freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> recipesFound  [in template "upgrade-asciidoc.ftl" at line 46, column 6]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
	- Failed at: #if recipesFound  [in template "upgrade-asciidoc.ftl" at line 46, column 1]
----
	at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134)
	at freemarker.core.UnexpectedTypeException.newDescriptionBuilder(UnexpectedTypeException.java:85)
	at freemarker.core.UnexpectedTypeException.<init>(UnexpectedTypeException.java:48)
	at freemarker.core.NonBooleanException.<init>(NonBooleanException.java:47)
	at freemarker.core.Expression.modelToBoolean(Expression.java:195)
	at freemarker.core.Expression.evalToBoolean(Expression.java:178)
	at freemarker.core.Expression.evalToBoolean(Expression.java:163)
	at freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:48)
	at freemarker.core.Environment.visit(Environment.java:347)
	at freemarker.core.Environment.visit(Environment.java:353)
	at freemarker.core.Environment.process(Environment.java:326)
	at freemarker.template.Template.process(Template.java:383)
	at org.springframework.sbm.boot.upgrade_24_25.actions.Boot_24_25_UpgradeReportAction.renderMarkdown(Boot_24_25_UpgradeReportAction.java:80)
	at org.springframework.sbm.boot.upgrade_24_25.actions.Boot_24_25_UpgradeReportAction.apply(Boot_24_25_UpgradeReportAction.java:69)
	at org.springframework.sbm.engine.recipe.Action.applyWithStatusEvent(Action.java:37)
	at org.springframework.sbm.engine.recipe.Recipe.lambda$apply$2(Recipe.java:97)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at org.springframework.sbm.engine.recipe.Recipe.apply(Recipe.java:97)
	at org.springframework.sbm.engine.commands.ApplyCommand.execute(ApplyCommand.java:70)
	at org.springframework.sbm.shell.ApplyShellCommand.apply(ApplyShellCommand.java:54)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
	at org.springframework.shell.Shell.evaluate(Shell.java:180)
	at org.springframework.shell.Shell.run(Shell.java:142)
	at org.springframework.shell.jline.InteractiveShellApplicationRunner.run(InteractiveShellApplicationRunner.java:84)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:793)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:346)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1365)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354)
	at org.springframework.sbm.SpringShellApplication.main(SpringShellApplication.java:27)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Action [org.springframework.sbm.boot.upgrade_24_25.actions.Boot_24_25_UpgradeReportAction] with description 'Create Upgrade Report for a Spring Boot 2.4 Application' failed: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> recipesFound  [in template "upgrade-asciidoc.ftl" at line 46, column 6]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
	- Failed at: #if recipesFound  [in template "upgrade-asciidoc.ftl" at line 46, column 1]
----
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.

Desktop (please complete the following information):

  • OS: Ubuntu 20.04
  • Version 11

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.