Repository: apache/camel-k (go)

Issue:
camel-rest should load automatically for routes using Rest DSL 
Currently `examples/RestWithRestlet.java` fails unless `--dependency=camel-rest` is explicitly set:
```
$ kamel run --name=rest-with-restlet --dependency=camel-restlet examples/RestWithRestlet.java --dev
...
[1] Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route2: Route(route2)[From[rest://get:/hello?consumerComponentName=r... because of Failed to resolve endpoint: rest://get:/hello?consumerComponentName=restlet&routeId=route2 due to: No component found with scheme: rest
[1] 	at org.apache.camel.reifier.RouteReifier.createRoute(RouteReifier.java:100)
[1] 	at org.apache.camel.impl.DefaultModel.start(DefaultModel.java:346)
[1] 	at org.apache.camel.impl.DefaultModel.startRoute(DefaultModel.java:320)
[1] 	at org.apache.camel.impl.DefaultModel.startRouteDefinitions(DefaultModel.java:313)
[1] 	at org.apache.camel.impl.DefaultModel.startRouteDefinitions(DefaultModel.java:292)
[1] 	at org.apache.camel.impl.AbstractModelCamelContext.startRouteDefinitions(AbstractModelCamelContext.java:330)
[1] 	at org.apache.camel.impl.engine.AbstractCamelContext.doStartCamel(AbstractCamelContext.java:2555)
[1] 	at org.apache.camel.impl.engine.AbstractCamelContext.lambda$doStart$2(AbstractCamelContext.java:2387)
[1] 	at org.apache.camel.impl.engine.AbstractCamelContext.doWithDefinedClassLoader(AbstractCamelContext.java:2404)
[1] 	at org.apache.camel.impl.engine.AbstractCamelContext.doStart(AbstractCamelContext.java:2385)
[1] 	at org.apache.camel.support.service.ServiceSupport.start(ServiceSupport.java:97)
[1] 	at org.apache.camel.impl.engine.AbstractCamelContext.start(AbstractCamelContext.java:2296)
[1] 	at org.apache.camel.main.Main.doStart(Main.java:117)
[1] 	at org.apache.camel.support.service.ServiceSupport.start(ServiceSupport.java:97)
[1] 	at org.apache.camel.main.MainSupport.run(MainSupport.java:196)
[1] 	at org.apache.camel.k.main.ApplicationRuntime.run(ApplicationRuntime.java:70)
[1] 	at org.apache.camel.k.main.Application.main(Application.java:44)
[1] Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: rest://get:/hello?consumerComponentName=restlet&routeId=route2 due to: No component found with scheme: rest
[1] 	at org.apache.camel.impl.engine.AbstractCamelContext.getEndpoint(AbstractCamelContext.java:779)
[1] 	at org.apache.camel.support.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:55)
[1] 	at org.apache.camel.impl.engine.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:114)
[1] 	at org.apache.camel.reifier.RouteReifier.doCreateRoute(RouteReifier.java:334)
[1] 	at org.apache.camel.reifier.RouteReifier.createRoute(RouteReifier.java:95)
[1] 	... 16 more
```

Pull request:
camel-rest should load automatically for routes using Rest DSL
Fixes #862

Patch:
diff --git a/deploy/olm-catalog/camel-k/1.0.0-M1-SNAPSHOT/camel-k.v1.0.0-M1-SNAPSHOT.clusterserviceversion.yaml b/deploy/olm-catalog/camel-k/1.0.0-M1-SNAPSHOT/camel-k.v1.0.0-M1-SNAPSHOT.clusterserviceversion.yaml
index d07fef540..62ef22854 100644
--- a/deploy/olm-catalog/camel-k/1.0.0-M1-SNAPSHOT/camel-k.v1.0.0-M1-SNAPSHOT.clusterserviceversion.yaml
+++ b/deploy/olm-catalog/camel-k/1.0.0-M1-SNAPSHOT/camel-k.v1.0.0-M1-SNAPSHOT.clusterserviceversion.yaml
@@ -17,10 +17,12 @@ metadata:
           "name": "example"
         },
         "spec": {
-          "source": {
-            "content": "// Add example Java code to create Integration",
-            "name": "Example.java"
-          }
+          "sources": [
+            {
+              "content": "from('timer:groovy?period=1s')\n  .setBody().simple('Hello world from Camel K!')\n  .to('log:info?showAll=false')",
+              "name": "example.groovy"
+            }
+          ]
         }
       },
       {
diff --git a/pkg/metadata/metadata.go b/pkg/metadata/metadata.go
index 89a9b5501..dd7392172 100644
--- a/pkg/metadata/metadata.go
+++ b/pkg/metadata/metadata.go
@@ -18,28 +18,23 @@ limitations under the License.
 package metadata
 
 import (
-	"sort"
-
-	"github.com/apache/camel-k/pkg/util/camel"
+	"github.com/scylladb/go-set/strset"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/gzip"
+	"github.com/apache/camel-k/pkg/util/camel"
 	"github.com/apache/camel-k/pkg/util/log"
+
 	src "github.com/apache/camel-k/pkg/util/source"
 )
 
 // ExtractAll returns metadata information from all listed source codes
 func ExtractAll(catalog *camel.RuntimeCatalog, sources []v1alpha1.SourceSpec) IntegrationMetadata {
 	// neutral metadata
-	meta := IntegrationMetadata{
-		Metadata: src.Metadata{
-			FromURIs:     []string{},
-			ToURIs:       []string{},
-			Dependencies: []string{},
-		},
-		PassiveEndpoints:    true,
-		RequiresHTTPService: false,
-	}
+	meta := NewIntegrationMetadata()
+	meta.PassiveEndpoints = true
+	meta.RequiresHTTPService = false
+
 	for _, source := range sources {
 		meta = merge(meta, Extract(catalog, source))
 	}
@@ -47,23 +42,21 @@ func ExtractAll(catalog *camel.RuntimeCatalog, sources []v1alpha1.SourceSpec) In
 }
 
 func merge(m1 IntegrationMetadata, m2 IntegrationMetadata) IntegrationMetadata {
-	deps := make(map[string]bool)
-	for _, d := range m1.Dependencies {
-		deps[d] = true
-	}
-	for _, d := range m2.Dependencies {
-		deps[d] = true
-	}
-	allDependencies := make([]string, 0)
-	for k := range deps {
-		allDependencies = append(allDependencies, k)
-	}
-	sort.Strings(allDependencies)
+	d := strset.Union(m1.Dependencies, m2.Dependencies)
+
+	f := make([]string, 0, len(m1.FromURIs)+len(m2.FromURIs))
+	f = append(f, m1.FromURIs...)
+	f = append(f, m2.FromURIs...)
+
+	t := make([]string, 0, len(m1.ToURIs)+len(m2.ToURIs))
+	t = append(t, m1.ToURIs...)
+	t = append(t, m2.ToURIs...)
+
 	return IntegrationMetadata{
 		Metadata: src.Metadata{
-			FromURIs:     append(m1.FromURIs, m2.FromURIs...),
-			ToURIs:       append(m1.ToURIs, m2.ToURIs...),
-			Dependencies: allDependencies,
+			FromURIs:     f,
+			ToURIs:       t,
+			Dependencies: d,
 		},
 		RequiresHTTPService: m1.RequiresHTTPService || m2.RequiresHTTPService,
 		PassiveEndpoints:    m1.PassiveEndpoints && m2.PassiveEndpoints,
@@ -80,7 +73,7 @@ func Extract(catalog *camel.RuntimeCatalog, source v1alpha1.SourceSpec) Integrat
 
 	language := source.InferLanguage()
 
-	m := IntegrationMetadata{}
+	m := NewIntegrationMetadata()
 
 	// TODO: handle error
 	_ = src.InspectorForLanguage(catalog, language).Extract(source, &m.Metadata)
diff --git a/pkg/metadata/types.go b/pkg/metadata/types.go
index 538553fb6..934da277c 100644
--- a/pkg/metadata/types.go
+++ b/pkg/metadata/types.go
@@ -17,7 +17,10 @@ limitations under the License.
 
 package metadata
 
-import "github.com/apache/camel-k/pkg/util/source"
+import (
+	"github.com/apache/camel-k/pkg/util/source"
+	"github.com/scylladb/go-set/strset"
+)
 
 // IntegrationMetadata contains aggregate metadata about all Camel routes in a integrations
 type IntegrationMetadata struct {
@@ -28,3 +31,14 @@ type IntegrationMetadata struct {
 	// external calls, including HTTP (useful to determine if the integration can scale to 0)
 	PassiveEndpoints bool
 }
+
+// NewIntegrationMetadata --
+func NewIntegrationMetadata() IntegrationMetadata {
+	return IntegrationMetadata{
+		Metadata: source.Metadata{
+			FromURIs:     make([]string, 0),
+			ToURIs:       make([]string, 0),
+			Dependencies: strset.New(),
+		},
+	}
+}
diff --git a/pkg/trait/dependencies.go b/pkg/trait/dependencies.go
index 453806c8d..7a2b94ba6 100644
--- a/pkg/trait/dependencies.go
+++ b/pkg/trait/dependencies.go
@@ -73,7 +73,7 @@ func (t *dependenciesTrait) Apply(e *Environment) error {
 		// main required by default
 		util.StringSliceUniqueAdd(&dependencies, "mvn:org.apache.camel.k/camel-k-runtime-main")
 
-		for _, d := range meta.Dependencies {
+		for _, d := range meta.Dependencies.List() {
 			util.StringSliceUniqueAdd(&dependencies, d)
 		}
 	}
diff --git a/pkg/util/source/inspector.go b/pkg/util/source/inspector.go
index fee4de658..65263cdb9 100644
--- a/pkg/util/source/inspector.go
+++ b/pkg/util/source/inspector.go
@@ -19,29 +19,29 @@ package source
 
 import (
 	"regexp"
-	"sort"
 	"strings"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/util"
 	"github.com/apache/camel-k/pkg/util/camel"
-	"github.com/scylladb/go-set/strset"
 )
 
 var (
-	singleQuotedFrom = regexp.MustCompile(`from\s*\(\s*'([a-z0-9-]+:[^']+)'`)
-	doubleQuotedFrom = regexp.MustCompile(`from\s*\(\s*"([a-z0-9-]+:[^"]+)"`)
-	singleQuotedTo   = regexp.MustCompile(`\.to\s*\(\s*'([a-z0-9-]+:[^']+)'`)
-	singleQuotedToD  = regexp.MustCompile(`\.toD\s*\(\s*'([a-z0-9-]+:[^']+)'`)
-	singleQuotedToF  = regexp.MustCompile(`\.toF\s*\(\s*'([a-z0-9-]+:[^']+)'`)
-	doubleQuotedTo   = regexp.MustCompile(`\.to\s*\(\s*"([a-z0-9-]+:[^"]+)"`)
-	doubleQuotedToD  = regexp.MustCompile(`\.toD\s*\(\s*"([a-z0-9-]+:[^"]+)"`)
-	doubleQuotedToF  = regexp.MustCompile(`\.toF\s*\(\s*"([a-z0-9-]+:[^"]+)"`)
+	singleQuotedFrom = regexp.MustCompile(`from\s*\(\s*'([a-zA-Z0-9-]+:[^']+)'`)
+	doubleQuotedFrom = regexp.MustCompile(`from\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`)
+	singleQuotedTo   = regexp.MustCompile(`\.to\s*\(\s*'([a-zA-Z0-9-]+:[^']+)'`)
+	singleQuotedToD  = regexp.MustCompile(`\.toD\s*\(\s*'([a-zA-Z0-9-]+:[^']+)'`)
+	singleQuotedToF  = regexp.MustCompile(`\.toF\s*\(\s*'([a-zA-Z0-9-]+:[^']+)'`)
+	doubleQuotedTo   = regexp.MustCompile(`\.to\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`)
+	doubleQuotedToD  = regexp.MustCompile(`\.toD\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`)
+	doubleQuotedToF  = regexp.MustCompile(`\.toF\s*\(\s*"([a-zA-Z0-9-]+:[^"]+)"`)
 
 	additionalDependencies = map[string]string{
-		".*JsonLibrary\\.Jackson.*": "camel:jackson",
-		".*\\.hystrix().*":          "camel:hystrix",
-		".*<hystrix>.*":             "camel:hystrix",
+		`.*JsonLibrary\.Jackson.*`:      "camel:jackson",
+		`.*\.hystrix().*`:               "camel:hystrix",
+		`.*restConfiguration().*`:       "camel:rest",
+		`.*rest(("[a-zA-Z0-9-/]+")*).*`: "camel:rest",
+		`^\s*rest\s*{.*`:                "camel:rest",
 	}
 )
 
@@ -102,30 +102,22 @@ func (i baseInspector) Extract(v1alpha1.SourceSpec, *Metadata) error {
 }
 
 // discoverDependencies returns a list of dependencies required by the given source code
-func (i *baseInspector) discoverDependencies(source v1alpha1.SourceSpec, meta *Metadata) []string {
+func (i *baseInspector) discoverDependencies(source v1alpha1.SourceSpec, meta *Metadata) {
 	uris := util.StringSliceJoin(meta.FromURIs, meta.ToURIs)
-	candidates := strset.New()
-	candidates.Add(meta.Dependencies...)
 
 	for _, uri := range uris {
 		candidateComp := i.decodeComponent(uri)
 		if candidateComp != "" {
-			candidates.Add(candidateComp)
+			meta.Dependencies.Add(candidateComp)
 		}
 	}
 
 	for pattern, dep := range additionalDependencies {
 		pat := regexp.MustCompile(pattern)
 		if pat.MatchString(source.Content) {
-			candidates.Add(dep)
+			meta.Dependencies.Add(dep)
 		}
 	}
-
-	components := candidates.List()
-
-	sort.Strings(components)
-
-	return components
 }
 
 func (i *baseInspector) decodeComponent(uri string) string {
diff --git a/pkg/util/source/inspector_groovy.go b/pkg/util/source/inspector_groovy.go
index 62db62937..47239564d 100644
--- a/pkg/util/source/inspector_groovy.go
+++ b/pkg/util/source/inspector_groovy.go
@@ -46,7 +46,8 @@ func (i GroovyInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata) err
 
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
-	meta.Dependencies = i.discoverDependencies(source, meta)
+
+	i.discoverDependencies(source, meta)
 
 	return nil
 }
diff --git a/pkg/util/source/inspector_java_script.go b/pkg/util/source/inspector_java_script.go
index 87d53eae8..0b23a6a26 100644
--- a/pkg/util/source/inspector_java_script.go
+++ b/pkg/util/source/inspector_java_script.go
@@ -46,7 +46,8 @@ func (i JavaScriptInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata)
 
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
-	meta.Dependencies = i.discoverDependencies(source, meta)
+
+	i.discoverDependencies(source, meta)
 
 	return nil
 }
diff --git a/pkg/util/source/inspector_java_source.go b/pkg/util/source/inspector_java_source.go
index 938e75bf6..0bb04047e 100644
--- a/pkg/util/source/inspector_java_source.go
+++ b/pkg/util/source/inspector_java_source.go
@@ -42,7 +42,8 @@ func (i JavaSourceInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata)
 
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
-	meta.Dependencies = i.discoverDependencies(source, meta)
+
+	i.discoverDependencies(source, meta)
 
 	return nil
 }
diff --git a/pkg/util/source/inspector_kotlin.go b/pkg/util/source/inspector_kotlin.go
index 9277f9b2d..1268455e1 100644
--- a/pkg/util/source/inspector_kotlin.go
+++ b/pkg/util/source/inspector_kotlin.go
@@ -42,7 +42,8 @@ func (i KotlinInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata) err
 
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
-	meta.Dependencies = i.discoverDependencies(source, meta)
+
+	i.discoverDependencies(source, meta)
 
 	return nil
 }
diff --git a/pkg/util/source/inspector_xml.go b/pkg/util/source/inspector_xml.go
index 923bd4055..fbf13a295 100644
--- a/pkg/util/source/inspector_xml.go
+++ b/pkg/util/source/inspector_xml.go
@@ -43,6 +43,10 @@ func (i XMLInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata) error
 
 		if se, ok := t.(xml.StartElement); ok {
 			switch se.Name.Local {
+			case "rest", "restConfiguration":
+				meta.Dependencies.Add("camel:rest")
+			case "hystrix":
+				meta.Dependencies.Add("camel:hystrix")
 			case "from", "fromF":
 				for _, a := range se.Attr {
 					if a.Name.Local == "uri" {
@@ -59,7 +63,7 @@ func (i XMLInspector) Extract(source v1alpha1.SourceSpec, meta *Metadata) error
 		}
 	}
 
-	meta.Dependencies = i.discoverDependencies(source, meta)
+	i.discoverDependencies(source, meta)
 
 	return nil
 }
diff --git a/pkg/util/source/inspector_yaml.go b/pkg/util/source/inspector_yaml.go
index 64676d6bc..93e8781d3 100644
--- a/pkg/util/source/inspector_yaml.go
+++ b/pkg/util/source/inspector_yaml.go
@@ -47,12 +47,19 @@ func (inspector YAMLInspector) Extract(source v1alpha1.SourceSpec, meta *Metadat
 		}
 	}
 
-	meta.Dependencies = inspector.discoverDependencies(source, meta)
+	inspector.discoverDependencies(source, meta)
 
 	return nil
 }
 
 func (inspector YAMLInspector) parseStep(key string, content interface{}, meta *Metadata) error {
+	switch key {
+	case "rest":
+		meta.Dependencies.Add("camel:rest")
+	case "hystrix":
+		meta.Dependencies.Add("camel:hystrix")
+	}
+
 	var maybeURI string
 
 	switch t := content.(type) {
diff --git a/pkg/util/source/types.go b/pkg/util/source/types.go
index 1b89b12ff..09f727a4f 100644
--- a/pkg/util/source/types.go
+++ b/pkg/util/source/types.go
@@ -17,6 +17,8 @@ limitations under the License.
 
 package source
 
+import "github.com/scylladb/go-set/strset"
+
 // Metadata --
 type Metadata struct {
 	// All starting URIs of defined routes
@@ -24,5 +26,5 @@ type Metadata struct {
 	// All end URIs of defined routes
 	ToURIs []string
 	// All inferred dependencies required to run the integration
-	Dependencies []string
+	Dependencies *strset.Set
 }
diff --git a/pkg/util/source/util.go b/pkg/util/source/util.go
deleted file mode 100644
index 63c5f51fd..000000000
--- a/pkg/util/source/util.go
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package source


Test patch:
diff --git a/e2e/backward_compat_test.go b/e2e/backward_compat_test.go
new file mode 100644
index 000000000..54573aa26
--- /dev/null
+++ b/e2e/backward_compat_test.go
@@ -0,0 +1,81 @@
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package e2e
+
+import (
+	"testing"
+
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+	. "github.com/onsi/gomega"
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+func TestBackwardCompatibility(t *testing.T) {
+	withNewTestNamespace(func(ns string) {
+		RegisterTestingT(t)
+
+		data := `
+apiVersion: ` + v1alpha1.SchemeGroupVersion.String() + `
+kind: Integration
+metadata:
+  name: example
+  namespace: ` + ns + `
+spec:
+  thisDoesNotBelongToSpec: hi
+  sources:
+  - name: hello.groovy
+status:
+  thisNeitherBelongs:
+    at: all
+`
+
+		obj, err := kubernetes.LoadRawResourceFromYaml(data)
+		assert.Nil(t, err)
+		err = testClient.Create(testContext, obj)
+		assert.Nil(t, err)
+
+		integration := v1alpha1.NewIntegration(ns, "example")
+		key, err := client.ObjectKeyFromObject(&integration)
+		assert.Nil(t, err)
+
+		unstr := unstructured.Unstructured{
+			Object: map[string]interface{}{
+				"kind":       "Integration",
+				"apiVersion": v1alpha1.SchemeGroupVersion.String(),
+			},
+		}
+		err = testClient.Get(testContext, key, &unstr)
+		assert.Nil(t, err)
+		spec := unstr.Object["spec"]
+		assert.NotNil(t, spec)
+		attr := spec.(map[string]interface{})["thisDoesNotBelongToSpec"]
+		assert.Equal(t, "hi", attr)
+
+		err = testClient.Get(testContext, key, &integration)
+		assert.Nil(t, err)
+		assert.Equal(t, 1, len(integration.Spec.Sources))
+		assert.Equal(t, "hello.groovy", integration.Spec.Sources[0].Name)
+	})
+}
diff --git a/pkg/metadata/metadata_dependencies_test.go b/pkg/metadata/metadata_dependencies_test.go
index 08fcb96a2..f0ad794a5 100644
--- a/pkg/metadata/metadata_dependencies_test.go
+++ b/pkg/metadata/metadata_dependencies_test.go
@@ -45,8 +45,8 @@ func TestDependenciesJavaSource(t *testing.T) {
 	assert.Nil(t, err)
 
 	meta := Extract(catalog, code)
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:amqp", "camel:log", "camel:telegram", "camel:timer", "camel:twitter"}, meta.Dependencies)
+
+	assert.ElementsMatch(t, []string{"camel:amqp", "camel:log", "camel:telegram", "camel:timer", "camel:twitter"}, meta.Dependencies.List())
 }
 
 func TestDependenciesJavaScript(t *testing.T) {
@@ -68,8 +68,7 @@ func TestDependenciesJavaScript(t *testing.T) {
 
 	meta := Extract(catalog, code)
 
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:amqp", "camel:log", "camel:telegram", "camel:timer"}, meta.Dependencies)
+	assert.ElementsMatch(t, []string{"camel:amqp", "camel:log", "camel:telegram", "camel:timer"}, meta.Dependencies.List())
 }
 
 func TestDependenciesGroovy(t *testing.T) {
@@ -93,8 +92,7 @@ func TestDependenciesGroovy(t *testing.T) {
 
 	meta := Extract(catalog, code)
 
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:amqp", "camel:log", "camel:telegram", "camel:timer", "camel:twitter"}, meta.Dependencies)
+	assert.ElementsMatch(t, []string{"camel:amqp", "camel:log", "camel:telegram", "camel:timer", "camel:twitter"}, meta.Dependencies.List())
 }
 
 func TestDependencies(t *testing.T) {
@@ -115,8 +113,7 @@ func TestDependencies(t *testing.T) {
 
 	meta := Extract(catalog, code)
 
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:http4", "camel:log", "camel:mock", "camel:twitter"}, meta.Dependencies)
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:log", "camel:mock", "camel:twitter"}, meta.Dependencies.List())
 }
 
 func TestJacksonDependency(t *testing.T) {
@@ -135,8 +132,7 @@ func TestJacksonDependency(t *testing.T) {
 
 	meta := Extract(catalog, code)
 
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:http4", "camel:jackson", "camel:log"}, meta.Dependencies)
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:jackson", "camel:log"}, meta.Dependencies.List())
 }
 
 func TestHystrixDependency(t *testing.T) {
@@ -159,8 +155,97 @@ func TestHystrixDependency(t *testing.T) {
 
 	meta := Extract(catalog, code)
 
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:http4", "camel:hystrix", "camel:log"}, meta.Dependencies)
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:hystrix", "camel:log"}, meta.Dependencies.List())
+}
+
+func TestRestDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+		DataSpec: v1alpha1.DataSpec{
+			Name: "Request.groovy",
+			Content: `
+                rest()
+                    .get("/api")
+                    .to("direct:get")
+			    from("http4:test")
+                    .to("log:info")
+		    `,
+		},
+		Language: v1alpha1.LanguageGroovy,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:rest", "camel:direct", "camel:log"}, meta.Dependencies.List())
+}
+
+func TestRestWithPathDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+		DataSpec: v1alpha1.DataSpec{
+			Name: "Request.groovy",
+			Content: `
+                rest("/test")
+                    .get("/api")
+                    .to("direct:get")
+			    from("http4:test")
+                    .to("log:info")
+		    `,
+		},
+		Language: v1alpha1.LanguageGroovy,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:rest", "camel:direct", "camel:log"}, meta.Dependencies.List())
+}
+
+func TestRestConfigurationDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+		DataSpec: v1alpha1.DataSpec{
+			Name: "Request.groovy",
+			Content: `
+                restConfiguration()
+                    .component("undertow")
+			    from("http4:test")
+                    .to("log:info")
+		    `,
+		},
+		Language: v1alpha1.LanguageGroovy,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:rest", "camel:log"}, meta.Dependencies.List())
+}
+
+func TestRestClosureDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+		DataSpec: v1alpha1.DataSpec{
+			Name: "Request.groovy",
+			Content: `
+                rest {
+                }    
+			    from("http4:test")
+                    .to("log:info")
+		    `,
+		},
+		Language: v1alpha1.LanguageGroovy,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:http4", "camel:rest", "camel:log"}, meta.Dependencies.List())
 }
 
 func TestXMLHystrixDependency(t *testing.T) {
@@ -186,6 +271,86 @@ func TestXMLHystrixDependency(t *testing.T) {
 
 	meta := Extract(catalog, code)
 
-	// assert all dependencies are found and sorted (removing duplicates)
-	assert.Equal(t, []string{"camel:direct", "camel:hystrix", "camel:kafka", "camel:log"}, meta.Dependencies)
+	assert.ElementsMatch(t, []string{"camel:direct", "camel:hystrix", "camel:kafka", "camel:log"}, meta.Dependencies.List())
+}
+
+func TestXMLRestDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+
+		DataSpec: v1alpha1.DataSpec{
+			Name: "routes.xml",
+			Content: `
+			<rest path="/say">
+		      <get uri="/hello">
+		        <to uri="direct:hello"/>
+		      </get>
+		      <get uri="/bye" consumes="application/json">
+		        <to uri="direct:bye"/>
+		      </get>
+		      <post uri="/bye">
+		        <to uri="mock:update"/>
+		      </post>
+		    </rest>
+		`,
+		},
+		Language: v1alpha1.LanguageXML,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:direct", "camel:rest", "camel:mock"}, meta.Dependencies.List())
+}
+
+const yamlWithRest = `
+- rest:
+    path: "/"
+    steps:
+        - to: "log:info"
+        - to: "direct:hello"            
+`
+const yamlWithHystrix = `
+- from:
+    uri: "direct:start"
+    steps:
+        - hystrix:
+            todo: "not implemented"                    
+`
+
+func TestYAMLRestDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+
+		DataSpec: v1alpha1.DataSpec{
+			Name:    "routes.yaml",
+			Content: yamlWithRest,
+		},
+		Language: v1alpha1.LanguageYaml,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:direct", "camel:rest", "camel:log"}, meta.Dependencies.List())
+}
+
+func TestYAMLHystrixDependency(t *testing.T) {
+	code := v1alpha1.SourceSpec{
+
+		DataSpec: v1alpha1.DataSpec{
+			Name:    "routes.yaml",
+			Content: yamlWithHystrix,
+		},
+		Language: v1alpha1.LanguageYaml,
+	}
+
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	meta := Extract(catalog, code)
+
+	assert.ElementsMatch(t, []string{"camel:direct", "camel:hystrix"}, meta.Dependencies.List())
 }
diff --git a/pkg/trait/dependencies_test.go b/pkg/trait/dependencies_test.go
index e795fa803..fd9ae249f 100644
--- a/pkg/trait/dependencies_test.go
+++ b/pkg/trait/dependencies_test.go
@@ -80,7 +80,11 @@ func TestIntegrationDefaultDeps(t *testing.T) {
 	assert.Nil(t, err)
 	assert.ElementsMatch(
 		t,
-		[]string{"camel:direct", "camel:log", "mvn:org.apache.camel.k/camel-k-loader-java", "mvn:org.apache.camel.k/camel-k-runtime-main"},
+		[]string{
+			"camel:direct",
+			"camel:log",
+			"mvn:org.apache.camel.k/camel-k-loader-java",
+			"mvn:org.apache.camel.k/camel-k-runtime-main"},
 		e.Integration.Status.Dependencies,
 	)
 }
@@ -121,7 +125,13 @@ func TestIntegrationCustomDeps(t *testing.T) {
 	err = trait.Apply(e)
 	assert.Nil(t, err)
 	assert.ElementsMatch(t,
-		[]string{"camel:direct", "camel:log", "camel:undertow", "org.foo:bar", "mvn:org.apache.camel.k/camel-k-loader-java", "mvn:org.apache.camel.k/camel-k-runtime-main"},
+		[]string{
+			"camel:direct",
+			"camel:log",
+			"camel:undertow",
+			"org.foo:bar",
+			"mvn:org.apache.camel.k/camel-k-loader-java",
+			"mvn:org.apache.camel.k/camel-k-runtime-main"},
 		e.Integration.Status.Dependencies,
 	)
 }
@@ -168,7 +178,12 @@ func TestIntegrationAutoGeneratedDeps(t *testing.T) {
 	assert.Nil(t, err)
 	assert.ElementsMatch(
 		t,
-		[]string{"camel:direct", "camel:log", "mvn:org.apache.camel.k/camel-k-loader-java", "mvn:org.apache.camel.k/camel-k-loader-xml",
+		[]string{
+			"camel:direct",
+			"camel:log",
+			"camel:rest",
+			"mvn:org.apache.camel.k/camel-k-loader-java",
+			"mvn:org.apache.camel.k/camel-k-loader-xml",
 			"mvn:org.apache.camel.k/camel-k-runtime-main"},
 		e.Integration.Status.Dependencies,
 	)