ABAP Cleaner es una herramienta de código abierto que limpia, formatea y moderniza automáticamente el código ABAP. Aplica más de 60 reglas de limpieza y ayuda a mantener estándares de código uniformes en todo el equipo.
¿Qué es ABAP Cleaner?
ABAP Cleaner analiza código ABAP y lo transforma automáticamente según reglas configurables. A diferencia del Pretty Printer, ABAP Cleaner va mucho más allá del simple formateo y también moderniza construcciones del lenguaje.
| Aspecto | Pretty Printer | ABAP Cleaner |
|---|---|---|
| Enfoque | Indentación, mayúsculas/minúsculas | Modernización completa del código |
| Reglas | ~5 reglas básicas | 60+ reglas configurables |
| Construcciones | Sin cambios | Modernización (p.ej. NEW en lugar de CREATE OBJECT) |
| Líneas vacías | Reglas simples | Agrupación inteligente |
| Comentarios | Sin cambios | Alineación y formateo |
| Rendimiento | - | Eliminación de sentencias innecesarias |
| Perfiles | Predefinidos | Configurables individualmente |
Ventajas
- Consistencia: Estilo de código uniforme en todo el equipo
- Productividad: Limpieza automática ahorra trabajo manual
- Modernización: Sintaxis antigua se actualiza automáticamente
- Legibilidad: Mejor estructuración y formateo
- Code Review: Menos discusiones sobre cuestiones de estilo
- Onboarding: Nuevos miembros del equipo escriben código conforme desde el inicio
Instalación en ADT
Requisitos previos
- Eclipse con ADT (ABAP Development Tools)
- Eclipse versión 2022-03 o posterior
- Java 11 o posterior
Instalación vía Eclipse Marketplace
- Abrir Eclipse y navegar a Help → Eclipse Marketplace
- Buscar “ABAP Cleaner”
- Clic en Install y seguir las instrucciones
- Reiniciar Eclipse
Instalación manual vía Update Site
Si el Marketplace no está disponible:
Help → Install New Software...
URL del Update Site:https://sap.github.io/abap-cleaner/updatesite
Features disponibles:☑ ABAP Cleaner
→ Next → Accept License → Finish → Restart EclipseVerificar instalación
Después del reinicio, ABAP Cleaner debería estar disponible:
┌──────────────────────────────────────────────────────────────┐│ ADT Toolbar │├──────────────────────────────────────────────────────────────┤│ ││ [📁] [💾] [↩️] [↪️] ... [🧹 ABAP Cleaner] ││ ││ O: Source → Clean Up With Interactive ABAP Cleaner... ││ Atajo: Ctrl+4 (configurable) ││ │└──────────────────────────────────────────────────────────────┘Reglas de limpieza más importantes
ABAP Cleaner agrupa sus reglas en categorías. Estas son las más importantes:
1. Empty Lines - Optimizar líneas vacías
Agrupación inteligente de bloques de código:
Antes:
METHOD process_order.
DATA lv_status TYPE string. DATA lv_amount TYPE p DECIMALS 2.
SELECT SINGLE status FROM zorders INTO lv_status WHERE order_id = iv_order_id.
IF lv_status = 'OPEN'. lv_amount = calculate_total( ).
update_order( lv_amount ). ENDIF.
ENDMETHOD.Después:
METHOD process_order. DATA lv_status TYPE string. DATA lv_amount TYPE p DECIMALS 2.
SELECT SINGLE status FROM zorders INTO lv_status WHERE order_id = iv_order_id.
IF lv_status = 'OPEN'. lv_amount = calculate_total( ). update_order( lv_amount ). ENDIF.ENDMETHOD.2. Declarations - Modernizar declaraciones
Antes:
DATA: lv_count TYPE i, lt_items TYPE TABLE OF zitem, ls_item TYPE zitem, lo_processor TYPE REF TO zcl_processor.
CREATE OBJECT lo_processor.CLEAR lt_items.Después:
DATA lv_count TYPE i.DATA lt_items TYPE TABLE OF zitem.DATA ls_item TYPE zitem.DATA lo_processor TYPE REF TO zcl_processor.
lo_processor = NEW #( ).CLEAR lt_items.3. Syntax - Usar sintaxis ABAP moderna
Antes:
CALL METHOD lo_service->get_data EXPORTING iv_id = lv_id RECEIVING rt_data = lt_data.
IF lt_data IS INITIAL. " ...ENDIF.
LOOP AT lt_data INTO ls_data. MOVE-CORRESPONDING ls_data TO ls_result. APPEND ls_result TO lt_result.ENDLOOP.Después:
lt_data = lo_service->get_data( iv_id = lv_id ).
IF lt_data IS INITIAL. " ...ENDIF.
LOOP AT lt_data INTO DATA(ls_data). lt_result = VALUE #( BASE lt_result ( CORRESPONDING #( ls_data ) ) ).ENDLOOP.4. Commands - Eliminar comandos innecesarios
Antes:
CLEAR lv_result.lv_result = calculate_value( ).
IF sy-subrc = 0. " ÉxitoENDIF.
MOVE lv_source TO lv_target.Después:
lv_result = calculate_value( ).
IF sy-subrc = 0. " ÉxitoENDIF.
lv_target = lv_source.5. Alignment - Mejorar alineación
Antes:
ls_order-order_id = lv_id.ls_order-customer = lv_customer.ls_order-status = 'NEW'.ls_order-created_at = sy-datum.ls_order-created_by = sy-uname.ls_order-amount = lv_amount.Después:
ls_order-order_id = lv_id.ls_order-customer = lv_customer.ls_order-status = 'NEW'.ls_order-created_at = sy-datum.ls_order-created_by = sy-uname.ls_order-amount = lv_amount.6. Pretty Print - Formateo
Antes:
IF LV_STATUS='OPEN'AND LV_AMOUNT>100. CALL METHOD LO_SERVICE->PROCESS(EXPORTING IV_ID=LV_ID CHANGING CT_DATA=LT_DATA).ENDIF.Después:
IF lv_status = 'OPEN' AND lv_amount > 100. lo_service->process( EXPORTING iv_id = lv_id CHANGING ct_data = lt_data ).ENDIF.7. Inline Declarations - Usar VALUE y NEW
Antes:
DATA lt_orders TYPE TABLE OF zorder.DATA ls_order TYPE zorder.DATA lo_service TYPE REF TO zcl_order_service.
CREATE OBJECT lo_service EXPORTING iv_client = sy-mandt.
ls_order-order_id = '12345'.ls_order-status = 'NEW'.APPEND ls_order TO lt_orders.Después:
DATA(lo_service) = NEW zcl_order_service( iv_client = sy-mandt ).
DATA(lt_orders) = VALUE zorders_t( ( order_id = '12345' status = 'NEW' )).8. Comments - Formatear comentarios
Antes:
"Este método calcula el precio total"incl. IVA y descuento."Parámetro: iv_net_price - Precio neto" iv_discount - Descuento en porcentaje"Retorno: Precio brutoMETHOD calculate_gross_price.Después:
" Este método calcula el precio total" incl. IVA y descuento." Parámetro: iv_net_price - Precio neto" iv_discount - Descuento en porcentaje" Retorno: Precio brutoMETHOD calculate_gross_price.Configuración y perfiles
Concepto de perfiles
ABAP Cleaner usa perfiles para la configuración. Un perfil define qué reglas están activas y cómo se aplican.
┌──────────────────────────────────────────────────────────────┐│ Profile Manager │├──────────────────────────────────────────────────────────────┤│ ││ Perfiles: ││ ┌────────────────────────────────────────────────────────┐ ││ │ [★] Default │ ││ │ [ ] Team Standard │ ││ │ [ ] Strict Modernization │ ││ │ [ ] Minimal Changes │ ││ │ [ ] + Crear nuevo perfil... │ ││ └────────────────────────────────────────────────────────┘ ││ ││ [ Editar ] [ Copiar ] [ Eliminar ] [ Exportar ] [ Importar ] ││ │└──────────────────────────────────────────────────────────────┘Crear y configurar perfil
- Window → Preferences → ABAP Cleaner abrir
- Profiles seleccionar
- Create new profile clic
Configuración de reglas
Cada regla puede configurarse individualmente:
┌──────────────────────────────────────────────────────────────┐│ Rule Configuration: "Use inline declarations" │├──────────────────────────────────────────────────────────────┤│ ││ ☑ Regla habilitada ││ ││ Opciones: ││ ┌────────────────────────────────────────────────────────┐ ││ │ Convertir declaraciones DATA: │ ││ │ ○ Solo si se usa una vez │ ││ │ ● Si se usa en el mismo bloque │ ││ │ ○ Siempre (agresivo) │ ││ │ │ ││ │ ☑ Convertir FIELD-SYMBOLS │ ││ │ ☑ Mantener declaraciones para tipos complejos │ ││ │ ☐ Convertir incluso si se pierde el tipo │ ││ └────────────────────────────────────────────────────────┘ ││ ││ Vista previa: ││ ┌─────────────────────────┐ ┌─────────────────────────┐ ││ │ DATA lv_name TYPE │ │ DATA(lv_name) = │ ││ │ string. │→│ get_name( ). │ ││ │ lv_name = get_name( │ │ │ ││ └─────────────────────────┘ └─────────────────────────┘ ││ │└──────────────────────────────────────────────────────────────┘Exportar y compartir perfil
Los perfiles pueden exportarse como archivo JSON y compartirse en el equipo:
{ "profileName": "Team Standard", "rules": { "EmptyLinesInClassDefinition": { "enabled": true, "maxEmptyLines": 1 }, "UseInlineDeclaration": { "enabled": true, "convertFieldSymbols": true, "onlyIfUsedOnce": false }, "ReplaceCreateObject": { "enabled": true }, "RemoveUnusedVariables": { "enabled": false } }}Distribuir en el equipo:
1. Exportar perfil: Preferences → ABAP Cleaner → Export Profile2. Colocar archivo JSON en repositorio Git: /config/abap-cleaner-profile.json3. Miembros del equipo importan: Preferences → ABAP Cleaner → Import ProfileUso diario
Modo interactivo
El modo interactivo muestra todos los cambios antes de aplicarlos:
Atajo: Ctrl+4 (o Source → Clean Up With Interactive ABAP Cleaner...)┌──────────────────────────────────────────────────────────────┐│ Interactive ABAP Cleaner │├──────────────────────────────────────────────────────────────┤│ ││ Regla: "Replace obsolete ADD with modern syntax" ││ ││ ┌─────────────────────────────┬─────────────────────────┐ ││ │ Antes │ Después │ ││ ├─────────────────────────────┼─────────────────────────┤ ││ │ ADD 1 TO lv_count. │ lv_count += 1. │ ││ │ ADD lv_amount TO lv_total. │ lv_total += lv_amount. │ ││ └─────────────────────────────┴─────────────────────────┘ ││ ││ [✓ Aplicar] [✗ Omitir] [Aplicar todo] [Omitir todo] [Info] ││ ││ Cambios: 2 de 15 aplicados | Perfil: Team Standard ││ │└──────────────────────────────────────────────────────────────┘Modo automático
Aplicar todas las reglas sin consulta:
Atajo: Ctrl+Shift+4 (o Source → Clean Up With Automatic ABAP Cleaner)Limpieza al guardar
ABAP Cleaner puede ejecutarse automáticamente al guardar:
Preferences → ABAP Cleaner → Clean-up on save
☑ Habilitar limpieza al guardar Perfil: [Team Standard ▼]
Alcance: ○ Solo método actual ● Bloques de código modificados ○ Código fuente completo
☑ Mostrar notificación después de limpiezaConfigurar atajos de teclado
Window → Preferences → General → Keys
Buscar: "ABAP Cleaner"
Resultados:- Clean Up With Interactive ABAP Cleaner: Ctrl+4- Clean Up With Automatic ABAP Cleaner: Ctrl+Shift+4- Open ABAP Cleaner Preferences: Ctrl+Shift+Alt+4Ejemplo completo antes/después
Antes: Código Legacy
CLASS zcl_order_processor DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS: process_order IMPORTING iv_order_id TYPE zorder_id RETURNING VALUE(rv_success) TYPE abap_bool RAISING zcx_order_error.
PRIVATE SECTION.
DATA: mv_client TYPE mandt. DATA: mo_logger TYPE REF TO zcl_logger.
ENDCLASS.
CLASS zcl_order_processor IMPLEMENTATION.
METHOD process_order.
DATA: lv_status TYPE zorder_status, lt_items TYPE TABLE OF zorder_item, ls_item TYPE zorder_item, lv_total TYPE p DECIMALS 2, lo_validator TYPE REF TO zcl_order_validator.
CREATE OBJECT lo_validator.
CLEAR lv_total.
SELECT SINGLE status FROM zorders INTO lv_status WHERE order_id EQ iv_order_id.
IF sy-subrc NE 0. RAISE EXCEPTION TYPE zcx_order_error. ENDIF.
IF lv_status EQ 'CLOSED'. rv_success = abap_false. RETURN. ENDIF.
SELECT * FROM zorder_items INTO TABLE lt_items WHERE order_id EQ iv_order_id.
LOOP AT lt_items INTO ls_item. ADD ls_item-amount TO lv_total. ENDLOOP.
CALL METHOD lo_validator->validate EXPORTING iv_order_id = iv_order_id iv_total = lv_total RECEIVING rv_valid = DATA(lv_valid).
IF lv_valid EQ abap_true. UPDATE zorders SET status = 'PROCESSING' WHERE order_id = iv_order_id. rv_success = abap_true. ELSE. rv_success = abap_false. ENDIF.
ENDMETHOD.
ENDCLASS.Después: Código modernizado
CLASS zcl_order_processor DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS process_order IMPORTING iv_order_id TYPE zorder_id RETURNING VALUE(rv_success) TYPE abap_bool RAISING zcx_order_error.
PRIVATE SECTION. DATA mv_client TYPE mandt. DATA mo_logger TYPE REF TO zcl_logger.ENDCLASS.
CLASS zcl_order_processor IMPLEMENTATION. METHOD process_order. DATA(lo_validator) = NEW zcl_order_validator( ).
SELECT SINGLE status FROM zorders INTO @DATA(lv_status) WHERE order_id = @iv_order_id.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE zcx_order_error. ENDIF.
IF lv_status = 'CLOSED'. rv_success = abap_false. RETURN. ENDIF.
SELECT * FROM zorder_items INTO TABLE @DATA(lt_items) WHERE order_id = @iv_order_id.
DATA(lv_total) = REDUCE #( INIT sum = 0 FOR ls_item IN lt_items NEXT sum += ls_item-amount ).
DATA(lv_valid) = lo_validator->validate( iv_order_id = iv_order_id iv_total = lv_total ).
IF lv_valid = abap_true. UPDATE zorders SET status = 'PROCESSING' WHERE order_id = iv_order_id. rv_success = abap_true. ELSE. rv_success = abap_false. ENDIF. ENDMETHOD.ENDCLASS.Resumen de cambios
| Categoría | Cambio |
|---|---|
| Líneas vacías | Líneas vacías innecesarias eliminadas, agrupación lógica |
| Declaraciones | Declaraciones DATA: encadenadas separadas |
| CREATE OBJECT | Reemplazado por NEW #( ) |
| CLEAR | CLEAR innecesario eliminado (variable se asigna directamente) |
| CALL METHOD | Escritura funcional utilizada |
| EQ/NE | Reemplazado por =/<> |
| Inline DATA | Declaraciones inline donde tiene sentido |
| REDUCE | LOOP AT con ADD reemplazado por REDUCE |
| Alignment | Alineación consistente de parámetros |
Integración en CI/CD
ABAP Cleaner puede usarse como parte del pipeline CI/CD para verificar estándares de código:
name: ABAP Style Check
on: pull_request: paths: - 'src/**.abap'
jobs: style-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Setup Java uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin'
- name: Run ABAP Cleaner Check run: | # Descargar ABAP Cleaner CLI wget https://github.com/SAP/abap-cleaner/releases/latest/download/abap-cleaner-cli.jar
# Verificar si serían necesarios cambios de limpieza java -jar abap-cleaner-cli.jar \ --profile config/abap-cleaner-profile.json \ --check-only \ --source src/
- name: Upload Report if: failure() uses: actions/upload-artifact@v4 with: name: cleanup-report path: cleanup-report.txtMejores prácticas
| Tema | Recomendación |
|---|---|
| Selección de perfil | Comenzar con perfil Default, ajustar gradualmente |
| Estándar del equipo | Definir un perfil común para todo el equipo |
| Cleanup on Save | Activar para código consistente |
| Modo interactivo | En código legacy, primero verificar interactivamente |
| Code Review | Ejecutar cleanup antes del review |
| Nuevas reglas | Revisar nuevas reglas con actualizaciones de ABAP Cleaner |
| Excepciones | Reglas desactivables para archivos específicos |
| CI/CD | Integrar como verificación de estilo en pipeline |
| Migración | Limpiar código legacy gradualmente, no todo a la vez |
| Documentación | Documentar decisiones del perfil del equipo |
Temas relacionados
- gCTS - Gestión de transportes basada en Git
- CI/CD con ABAP Cloud - Pipelines automatizados
- Consejos y trucos ADT - Desarrollo eficiente en Eclipse