This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch bugfix/remove-empty-properties-annotation
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git

commit 062fab19fead819b7b7d764fbd79a54294b22acd
Author: Konrad Windszus <[email protected]>
AuthorDate: Sat May 9 17:42:19 2026 +0200

    Remove empty SCR @Properties annotation after migration
---
 .../scripts/migrate_annotations.py                 | 40 +++++++++++++++++++++
 .../scripts/tests/test_migrate_annotations.py      | 42 ++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/skills/osgi-scr-migrator/scripts/migrate_annotations.py 
b/skills/osgi-scr-migrator/scripts/migrate_annotations.py
index 70385722..03e3420f 100755
--- a/skills/osgi-scr-migrator/scripts/migrate_annotations.py
+++ b/skills/osgi-scr-migrator/scripts/migrate_annotations.py
@@ -246,6 +246,7 @@ class AnnotationMigrator:
                 self._generate_metatype_config()
 
             self._update_imports()
+            self._cleanup_empty_properties_annotations()
 
             return '\n'.join(self.lines), self.changes_made
         except Exception as e:
@@ -406,6 +407,7 @@ class AnnotationMigrator:
             'org.apache.felix.scr.annotations.Deactivate': 
'org.osgi.service.component.annotations.Deactivate',
             'org.apache.felix.scr.annotations.Modified': 
'org.osgi.service.component.annotations.Modified',
             'org.apache.felix.scr.annotations.Property': None,
+            'org.apache.felix.scr.annotations.Properties': None,
             'org.apache.felix.scr.annotations.Reference': 
'org.osgi.service.component.annotations.Reference',
             'org.apache.felix.scr.annotations.ReferenceCardinality': 
'org.osgi.service.component.annotations.ReferenceCardinality',
             'org.apache.felix.scr.annotations.ReferencePolicy': 
'org.osgi.service.component.annotations.ReferencePolicy',
@@ -1067,6 +1069,44 @@ class AnnotationMigrator:
                 self.lines.insert(insert_idx, f'import {new_import};')
                 insert_idx += 1
 
+    def _cleanup_empty_properties_annotations(self):
+        """Remove empty Felix SCR @Properties container annotations.
+
+        This cleanup is run after @Property annotations are removed, so 
containers
+        that become empty do not remain in migrated code.
+        """
+        i = 0
+        while i < len(self.lines):
+            line = self.lines[i]
+
+            if '@Properties' in line and not line.strip().startswith('//'):
+                annotation = line
+                paren_count = line.count('(') - line.count(')')
+                annotation_lines = [i]
+                j = i + 1
+
+                while paren_count > 0 and j < len(self.lines):
+                    annotation += ' ' + self.lines[j].strip()
+                    annotation_lines.append(j)
+                    paren_count += self.lines[j].count('(') - 
self.lines[j].count(')')
+                    j += 1
+
+                compact = re.sub(r'\s+', '', annotation)
+                empty_forms = {
+                    '@Properties',
+                    '@Properties()',
+                    '@Properties({})',
+                    '@Properties(value={})',
+                }
+
+                if compact in empty_forms:
+                    for idx in reversed(annotation_lines):
+                        del self.lines[idx]
+                    self.changes_made = True
+                    continue
+
+            i += 1
+
 
 def migrate_file(file_path: Path, dry_run: bool = False, stats: MigrationStats 
= None) -> bool:
     """Migrate a single Java file."""
diff --git a/skills/osgi-scr-migrator/scripts/tests/test_migrate_annotations.py 
b/skills/osgi-scr-migrator/scripts/tests/test_migrate_annotations.py
index f15eb00d..7786e9ce 100644
--- a/skills/osgi-scr-migrator/scripts/tests/test_migrate_annotations.py
+++ b/skills/osgi-scr-migrator/scripts/tests/test_migrate_annotations.py
@@ -288,6 +288,48 @@ public class MyService {
         
self.assertIn('org.osgi.service.component.propertytypes.ServiceVendor', 
new_content)
         
self.assertIn('org.osgi.service.component.propertytypes.ServiceRanking', 
new_content)
 
+    def test_empty_properties_container_removed(self):
+        """Test that empty @Properties is removed after property migration."""
+        content = '''package com.example;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+
+@Component
+@Properties({
+    @Property(name = "service.vendor", value = "Apache Software Foundation")
+})
+public class MyService {
+}
+'''
+        stats = MigrationStats()
+        migrator = AnnotationMigrator(content, Path("test.java"), stats)
+        new_content, changed = migrator.migrate()
+
+        self.assertTrue(changed)
+        self.assertNotIn('@Properties', new_content)
+        self.assertNotIn('@Property', new_content)
+
+    def test_preexisting_empty_properties_removed(self):
+        """Test that pre-existing empty @Properties annotation is cleaned 
up."""
+        content = '''package com.example;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+
+@Component
+@Properties(value = { })
+public class MyService {
+}
+'''
+        stats = MigrationStats()
+        migrator = AnnotationMigrator(content, Path("test.java"), stats)
+        new_content, changed = migrator.migrate()
+
+        self.assertTrue(changed)
+        self.assertNotIn('@Properties', new_content)
+
 
 class TestReferenceMigration(unittest.TestCase):
     """Test @Reference migration."""

Reply via email to