К основному содержанию
правило официальный · GitHub

convert-jpa-to-spring-data-cosmos — правило для GitHub Copilot

Пошаговое правило для Copilot: переводит Spring Boot проект с JPA на Azure Cosmos DB через Spring Data Cosmos. Пригодится, когда миграция уже решена и нужен план.

Установить в GitHub Copilot · Вручную: положить файлы Все способы и платформы ↓
.github/instructions/convert-jpa-to-spring-data-cosmos.instructions.md
Открыть на GitHub

Что делает convert-jpa-to-spring-data-cosmos

Правило описывает миграцию Spring Boot приложения с JPA на Azure Cosmos DB. Внутри — план из девяти шагов: замена зависимостей в сборке, профиль cosmos с настройками, конфигурационный класс с аутентификацией через Azure Identity, перестройка сущностей и репозиториев, отдельный сервисный слой для связей, правка тестов и загрузка начальных данных через CommandLineRunner.

Сущности переделываются заметно: id меняется с Integer на String, вместо @Entity ставится @Container, добавляется @PartitionKey, а связи @OneToMany и @ManyToOne заменяются встроенными коллекциями или ссылками по идентификатору. Отдельный блок посвящён сущностям аутентификации: @JsonIgnore на пароле и authorities ломает сериализацию в Cosmos, поэтому вместо него советуется @JsonProperty, а authorities хранить как Set<String>. Если в проекте Thymeleaf или JSP, для свойств, которые читаются в шаблонах, правило предлагает держать transient-поле с @JsonIgnore рядом с хранимым списком идентификаторов.

В начале стоит явное ограничение: применять руководство только по прямой просьбе мигрировать на Cosmos. Само наличие JPA в проекте поводом не считается. Для конфигурации нужна зависимость com.azure:azure-identity и DefaultAzureCredential — аутентификация по ключу в примере не используется. Учтите, что идентификаторы становятся строками, поэтому придётся переписать все тесты и места, где раньше ожидалось число.

Какие задачи решает

  • заменить зависимости JPA на Azure Cosmos DB в Maven или Gradle
  • перевести сущности на @Container и @PartitionKey
  • починить сериализацию сущностей аутентификации в Cosmos
  • сохранить доступ к связям из Thymeleaf шаблонов после перехода на ID
  • переписать тесты под строковые идентификаторы

Примеры запросов агенту

  • Примени правило convert-jpa-to-spring-data-cosmos и переведи этот проект на Azure Cosmos DB
  • Замени JpaRepository на CosmosRepository в репозиториях этого модуля
  • Проверь сущность User: убери @JsonIgnore с полей, которые должны попадать в Cosmos

Как установить convert-jpa-to-spring-data-cosmos

Вручную: положить файлы

.github/instructions/convert-jpa-to-spring-data-cosmos.instructions.md

Поле applyTo задаёт, к каким файлам применять

По шагам, с командами для каждой платформы: AGENTS.md и CLAUDE.md: что это, кто читает и какой выбрать

Из того же набора674

Весь набор →
dataverse-python-agentic-workflows Правило для GitHub Copilot с концепциями агентных сценариев на Dataverse SDK для Python: автономные агенты, MCP, A2A и проверка качества данных. ★ 40 418звёзд репо csharp Правило задаёт Copilot стиль C#-кода: именование, nullable-типы, форматирование и работу с ASP.NET Core. Пригодится, если агент пишет по-разному в каждом файле. ★ 40 418звёзд репо copilot-thought-logging Правило заставляет Copilot вести файл Copilot-Processing.md с планом и отметками о выполнении, чтобы вы видели ход работы и могли его поправить. ★ 40 418звёзд репо copilot-sdk-java Правило подсказывает Copilot, как писать Java-приложения на GitHub Copilot SDK: инициализация клиента, сессии, асинхронные вызовы. ★ 40 418звёзд репо context-engineering Правило для GitHub Copilot: как раскладывать файлы, типы и комментарии, чтобы подсказки попадали в проект, а не в пустоту. ★ 40 418звёзд репо coldfusion-cfc Правило задаёт Copilot стандарты кода для ColdFusion-компонентов: CFScript, cfqueryparam, аккуратные геттеры и сеттеры. Пригодится, если в проекте есть файлы .cfc. ★ 40 418звёзд репо cmake-vcpkg Правило задаёт Copilot контекст проекта на C++: vcpkg в режиме манифеста, настройки через CMakePresets.json и сборка под MSVC, Clang и GCC. ★ 40 418звёзд репо azure-logic-apps-power-automate Правило для GitHub Copilot, которое подсказывает, как писать JSON-определения Azure Logic Apps и Power Automate: триггеры, действия, обработка ошибок. ★ 40 418звёзд репо

Похожие

spring-data-jpa giuseppe-trisciuoglio Шаблоны и правила для слоя персистентности на Spring Data JPA: создание репозиториев, пагинация, аудит сущностей и настройка транзакций. CX Codex +1 4 100установок jpa-patterns affaan-m Скилл подсказывает правила моделирования JPA-сущностей, устранения проблемы N+1 и настройки пула HikariCP в Spring Boot. Пригодится при написании репозиториев и оптимизации запросов. CX Codex +1 4 600установок java-spring-boot pluginagentmarketplace Скилл помогает создавать бэкенд на Spring Boot 3: настраивать REST API, аутентификацию через Spring Security, доступ к базам через Spring Data и мониторинг Actuator. CX Codex +1 11 800установок spring-boot-crud-patterns giuseppe-trisciuoglio Скилл собирает полный CRUD-слой для сервисов на Spring Boot 3: агрегаты, JPA-репозитории, DTO и REST-контроллеры по feature-архитектуре. CX Codex +1 3 900установок spring-boot-engineer https://github.com/Jeffallan Разворачивает архитектуру Spring Boot 3.x, контроллеры, репозитории Spring Data JPA и правила Spring Security 6. Пригодится при сборке REST API, реактивных сервисов и микросервисов на Java. CX Codex +1 8 400установок spring-boot-development manutej Скилл для ИИ-агента, который подсказывает, как писать Spring Boot: авто-конфигурация, внедрение зависимостей, REST-контроллеры, Spring Data и Spring Security. CX Codex +1 534установок

Рядом в теме «Бэкенд и API»

Всё по теме «Бэкенд и API» →

Вопросы о convert-jpa-to-spring-data-cosmos

Как установить convert-jpa-to-spring-data-cosmos в GitHub Copilot?

Положите файл по пути .github/instructions/convert-jpa-to-spring-data-cosmos.instructions.md в репозитории проекта.

Что делает это правило?

Ведёт Copilot по шагам миграции Spring Boot приложения с JPA на Azure Cosmos DB: зависимости, конфигурация, сущности, репозитории, сервисный слой, тесты.

Когда правило вообще применяется?

Только если вы прямо попросили мигрировать на Azure Cosmos DB. Обнаружение JPA в проекте само по себе миграцию не запускает.

Исходный текст

convert-jpa-to-spring-data-cosmos.instructions.md · MIT
---
description: 'Step-by-step guide for converting Spring Boot JPA applications to use Azure Cosmos DB with Spring Data Cosmos'
applyTo: '**/*.java,**/pom.xml,**/build.gradle,**/application*.properties'
---

# Convert Spring JPA project to Spring Data Cosmos

> **Guard:** Apply this guide ONLY when the user explicitly asks to migrate to Azure Cosmos DB. Detecting JPA in a project does not authorize a migration. Otherwise, follow the `java-hibernate-jpa` and Spring Boot guidance.

This generalized guide applies to any JPA to Spring Data Cosmos DB conversion project.

## High-level plan

1. Swap build dependencies (remove JPA, add Cosmos + Identity).
2. Add `cosmos` profile and properties.
3. Add Cosmos config with proper Azure identity authentication.
4. Transform entities (ids → `String`, add `@Container` and `@PartitionKey`, remove JPA mappings, adjust relationships).
5. Convert repositories (`JpaRepository` → `CosmosRepository`).
6. **Create service layer** for relationship management and template compatibility.
7. **CRITICAL**: Update ALL test files to work with String IDs and Cosmos repositories.
8. Seed data via `CommandLineRunner`.
9. **CRITICAL**: Test runtime functionality and fix template compatibility issues.

## Step-by-step

### Step 1 — Build dependencies

- **Maven** (`pom.xml`):
  - Remove dependency `spring-boot-starter-data-jpa`
  - Remove database-specific dependencies (H2, MySQL, PostgreSQL) unless needed elsewhere
  - Add `com.azure:azure-spring-data-cosmos:5.17.0` (or latest compatible version)
  - Add `com.azure:azure-identity:1.15.4` (required for DefaultAzureCredential)
- **Gradle**: Apply same dependency changes for Gradle syntax
- Remove testcontainers and JPA-specific test dependencies

### Step 2 — Properties and Configuration

- Create `src/main/resources/application-cosmos.properties`:
  ```properties
  azure.cosmos.uri=${COSMOS_URI:https://localhost:8081}
  azure.cosmos.database=${COSMOS_DATABASE:petclinic}
  azure.cosmos.populate-query-metrics=false
  azure.cosmos.enable-multiple-write-locations=false
  ```
- Update `src/main/resources/application.properties`:
  ```properties
  spring.profiles.active=cosmos
  ```

### Step 3 — Configuration class with Azure Identity

- Create `src/main/java/<rootpkg>/config/CosmosConfiguration.java`:
  ```java
  @Configuration
  @EnableCosmosRepositories(basePackages = "<rootpkg>")
  public class CosmosConfiguration extends AbstractCosmosConfiguration {

    @Value("${azure.cosmos.uri}")
    private String uri;

    @Value("${azure.cosmos.database}")
    private String dbName;

    @Bean
    public CosmosClientBuilder getCosmosClientBuilder() {
      return new CosmosClientBuilder().endpoint(uri).credential(new DefaultAzureCredentialBuilder().build());
    }

    @Override
    protected String getDatabaseName() {
      return dbName;
    }

    @Bean
    public CosmosConfig cosmosConfig() {
      return CosmosConfig.builder().enableQueryMetrics(false).build();
    }
  }

  ```
- **IMPORTANT**: Use `DefaultAzureCredentialBuilder().build()` instead of key-based authentication for production security

### Step 4 — Entity transformation

- Target all classes with JPA annotations (`@Entity`, `@MappedSuperclass`, `@Embeddable`)
- **Base entity changes**:
  - Change `id` field type from `Integer` to `String`
  - Add `@Id` and `@GeneratedValue` annotations
  - Add `@PartitionKey` field (typically `String partitionKey`)
  - Remove all `jakarta.persistence` imports
- **CRITICAL - Cosmos DB Serialization Requirements**:
  - **Remove ALL `@JsonIgnore` annotations** from fields that need to be persisted to Cosmos DB
  - **Authentication entities (User, Authority) MUST be fully serializable** - no `@JsonIgnore` on password, authorities, or other persisted fields
  - **Use `@JsonProperty` instead of `@JsonIgnore`** when you need to control JSON field names but still persist the data
  - **Common authentication serialization errors**: `Cannot pass null or empty values to constructor` usually means `@JsonIgnore` is blocking required field serialization
- **Entity-specific changes**:
  - Replace `@Entity` with `@Container(containerName = "<plural-entity-name>")`
  - Remove `@Table`, `@Column`, `@JoinColumn`, etc.
  - Remove relationship annotations (`@OneToMany`, `@ManyToOne`, `@ManyToMany`)
  - For relationships:
    - Embed collections for one-to-many (e.g., `List<Pet> pets` in Owner)
    - Use reference IDs for many-to-one (e.g., `String ownerId` in Pet)
    - **For complex relationships**: Store IDs but add transient properties for templates
  - Add constructor to set partition key: `setPartitionKey("entityType")`
- **CRITICAL - Authentication Entity Pattern**:
  - **For User entities with Spring Security**: Store authorities as `Set<String>` instead of `Set<Authority>` objects
  - **Example User entity transformation**:
    ```java
    @Container(containerName = "users")
    public class User {

      @Id
      private String id;

      @PartitionKey
      private String partitionKey = "user";

      private String login;
      private String password; // NO @JsonIgnore - must be serializable

      @JsonProperty("authorities") // Use @JsonProperty, not @JsonIgnore
      private Set<String> authorities = new HashSet<>(); // Store as strings

      // Add transient property for Spring Security compatibility if needed
      // @JsonIgnore - ONLY for transient properties not persisted to Cosmos
      private Set<Authority> authorityObjects = new HashSet<>();

      // Conversion methods between string authorities and Authority objects
      public void setAuthorityObjects(Set<Authority> authorities) {
        this.authorityObjects = authorities;
        this.authorities = authorities.stream().map(Authority::getName).collect(Collectors.toSet());
      }
    }

    ```
- **CRITICAL - Template Compatibility for Relationship Changes**:
  - **When converting relationships to ID references, preserve template access**
  - **Example**: If entity had `List<Specialty> specialties` → convert to:
    - Storage: `List<String> specialtyIds` (persisted to Cosmos)
    - Template: `@JsonIgnore private List<Specialty> specialties = new ArrayList<>()` (transient)
    - Add getters/setters for both properties
  - **Update entity method logic**: `getNrOfSpecialties()` should use the transient list
- **CRITICAL - Template Compatibility for Thymeleaf/JSP Applications**:
  - **Identify template property access**: Search for `${entity.relationshipProperty}` in `.html` files
  - **For each relationship property accessed in templates**:
    - **Storage**: Keep ID-based storage (e.g., `List<String> specialtyIds`)
    - **Template Access**: Add transient property with `@JsonIgnore` (e.g., `private List<Specialty> specialties = new ArrayList<>()`)
    - **Example**:

      ```java
      // Stored in Cosmos (persisted)
      private List<String> specialtyIds = new ArrayList<>();

      // For template access (transient)
      @JsonIgnore
      private List<Specialty> specialties = new ArrayList<>();

      // Getters/setters for both properties
      public List<String> getSpecialtyIds() {
        return specialtyIds;
      }

      public List<Specialty> getSpecialties() {
        return specialties;
      }

      ```

    - **Update count methods**: `getNrOfSpecialties()` should use transient list, not ID list
- **CRITICAL - Method Signature Conflicts**:
  - **When converting ID types from Integer to String, check for method signature conflicts**
  - **Common conflict**: `getPet(String name)` vs `getPet(String id)` - both have same signature
  - **Solution**: Rename methods to be specific:
    - `getPet(String id)` for ID-based lookup
    - `getPetByName(String name)` for name-based lookup
    - `getPetByName(String name, boolean ignoreNew)` for conditional name-based lookup
  - **Update ALL callers** of renamed methods in controllers and tests
- **Method updates for entities**:
  - Update `addVisit(Integer petId, Visit visit)` to `addVisit(String petId, Visit visit)`
  - Ensure all ID comparison logic uses `.equals()` instead of `==`

### Step 5 — Repository conversion

- Change all repository interfaces:
  - From: `extends JpaRepository<Entity, Integer>`
  - To: `extends CosmosRepository<Entity, String>`
- **Query method updates**:
  - Remove pagination parameters from custom queries
  - Change `Page<Entity> findByX(String param, Pageable pageable)` to `List<Entity> findByX(String param)`
  - Update `@Query` annotations to use Cosmos SQL syntax
  - **Replace custom method names**: `findPetTypes()` → `findAllOrderByName()`
  - **Update ALL references** to changed method names in controllers and formatters

### Step 6 — **Create service layer** for relationship management and template compatibility

- **CRITICAL**: Create service classes to bridge Cosmos document storage with existing template expectations
- **Purpose**: Handle relationship population and maintain template compatibility
- **Service pattern for each entity with relationships**:
  ```java
  @Service
  public class EntityService {

    private final EntityRepository entityRepository;
    private final RelatedRepository relatedRepository;

    public EntityService(EntityRepository entityRepository, RelatedRepository relatedRepository) {
      this.entityRepository = entityRepository;
      this.relatedRepository = relatedRepository;
    }

    public List<Entity> findAll() {
      List<Entity> entities = entityRepository.findAll();
      entities.forEach(this::populateRelationships);
      return entities;
    }

    public Optional<Entity> findById(String id) {
      Optional<Entity> entityOpt = entityRepository.findById(id);
      if (entityOpt.isPresent()) {
        Entity entity = entityOpt.get();
        populateRelationships(entity);
        return Optional.of(entity);
      }
      return Optional.empty();
    }

    private void populateRelationships(Entity entity) {
      if (entity.getRelatedIds() != null && !entity.getRelatedIds().isEmpty()) {
        List<Related> related = entity
          .getRelatedIds()
          .stream()
          .map(relatedRepository::findById)
          .filter(Optional::isPresent)
          .map(Optional::get)
          .collect(Collectors.toList());
        // Set transient property for template access
        entity.setRelated(related);
      }
    }
  }

  ```

### Step 6.5 — **Spring Security Integration** (CRITICAL for Authentication)

- **UserDetailsService Integration Pattern**:
  ```java
  @Service
  @Transactional
  public class DomainUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;
    private final AuthorityRepository authorityRepository;

    @Override
    public UserDetails loadUserByUsername(String login) {
      log.debug("Authenticating user: {}", login);

      return userRepository
        .findOneByLogin(login)
        .map(user -> createSpringSecurityUser(login, user))
        .orElseThrow(() -> new UsernameNotFoundException("User " + login + " was not found"));
    }

    private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
      if (!user.isActivated()) {
        throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
      }

      // Convert string authorities back to GrantedAuthority objects
      List<GrantedAuthority> grantedAuthorities = user
        .getAuthorities()
        .stream()
        .map(SimpleGrantedAuthority::new)
        .collect(Collectors.toList());

      return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), grantedAuthorities);
    }
  }

  ```
- **Key Authentication Requirements**:
  - User entity must be fully serializable (no `@JsonIgnore` on password/authorities)
  - Store authorities as `Set<String>` for Cosmos DB compatibility
  - Convert between string authorities and `GrantedAuthority` objects in UserDetailsService
  - Add comprehensive debugging logs to trace authentication flow
  - Handle activated/deactivated user states appropriately

#### **Template Relationship Population Pattern**

Each service method that returns entities for template rendering MUST populate transient properties:

```java
private void populateRelationships(Entity entity) {
  // For each relationship used in templates
  if (entity.getRelatedIds() != null && !entity.getRelatedIds().isEmpty()) {
    List<Related> relatedObjects = entity
      .getRelatedIds()
      .stream()
      .map(relatedRepository::findById)
      .filter(Optional::isPresent)
      .map(Optional::get)
      .collect(Collectors.toList());
    entity.setRelated(relatedObjects); // Set transient property
  }
}

```

#### **Critical Service Usage in Controllers**

- **Replace ALL direct repository calls** with service calls in controllers
- **Never return entities from repositories directly** to templates without relationship population
- **Update controllers** to use service layer instead of repositories directly
- **Controller pattern change**:

  ```java
  // OLD: Direct repository usage
  @Autowired
  private EntityRepository entityRepository;

  // NEW: Service layer usage
  @Autowired
  private EntityService entityService;
  // Update method calls
  // OLD: entityRepository.findAll()
  // NEW: entityService.findAll()

  ```

### Step 7 — Data seeding

- Create `@Component` implementing `CommandLineRunner`:
  ```java
  @Component
  public class DataSeeder implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
      if (ownerRepository.count() > 0) {
        return; // Data already exists
      }
      // Seed comprehensive test data with String IDs
      // Use meaningful ID patterns: "owner-1", "pet-1", "pettype-1", etc.
    }
  }

  ```
- **CRITICAL - BigDecimal Reflection Issues with JDK 17+**:
  - **If using BigDecimal fields**, you may encounter reflection errors during seeding
  - **Error pattern**: `Unable to make field private final java.math.BigInteger java.math.BigDecimal.intVal accessible`
  - **Solutions**:
    1. Use `Double` or `String` instead of `BigDecimal` for monetary values
    2. Add JVM argument: `--add-opens java.base/java.math=ALL-UNNAMED`
    3. Wrap BigDecimal operations in try-catch and handle gracefully
  - **The application will start successfully even if seeding fails** - check logs for seeding errors

### Step 8 — Test file conversion (CRITICAL SECTION)

**This step is often overlooked but essential for successful conversion**

#### A. **COMPILATION CHECK STRATEGY**

- **After each major change, run `mvn test-compile` to catch issues early**
- **Fix compilation errors systematically before proceeding**
- **Don't rely on IDE - Maven compilation reveals all issues**

#### B. **Search and Update ALL test files systematically**

**Use search tools to find and update every occurrence:**

- Search for: `int.*TEST.*ID` → Replace with: `String.*TEST.*ID = "test-xyz-1"`
- Search for: `setId\(\d+\)` → Replace with: `setId("test-id-X")`
- Search for: `findById\(\d+\)` → Replace with: `findById("test-id-X")`
- Search for: `\.findPetTypes\(\)` → Replace with: `.findAllOrderByName()`
- Search for: `\.findByLastNameStartingWith\(.*,.*Pageable` → Remove pagination parameter

#### C. Update test annotations and imports

- Replace `@DataJpaTest` with `@SpringBootTest` or appropriate slice test
- Remove `@AutoConfigureTestDatabase` annotations
- Remove `@Transactional` from tests (unless single-partition operations)
- Remove imports from `org.springframework.orm` package

#### D. Fix entity ID usage in ALL test files

**Critical files that MUST be updated (search entire test directory):**

- `*ControllerTests.java` - Path variables, entity creation, mock setup
- `*ServiceTests.java` - Repository interactions, entity IDs
- `EntityUtils.java` - Utility methods for ID handling
- `*FormatterTests.java` - Repository method calls
- `*ValidatorTests.java` - Entity creation with String IDs
- Integration test classes - Test data setup

#### E. **Fix Controller and Service classes affected by repository changes**

- **Update controllers that call repository methods with changed signatures**
- **Update formatters/converters that use repository methods**
- **Common files to check**:
  - `PetTypeFormatter.java` - often calls `findPetTypes()` method
  - `*Controller.java` - may have pagination logic to remove
  - Service classes that use repository methods

#### F. Update repository mocking in tests

- Remove pagination from repository mocks:
  - `given(repository.findByX(param, pageable)).willReturn(pageResult)`
  - → `given(repository.findByX(param)).willReturn(listResult)`
- Update method names in mocks:
  - `given(petTypeRepository.findPetTypes()).willReturn(types)`
  - → `given(petTypeRepository.findAllOrderByName()).willReturn(types)`

#### G. Fix utility classes used by tests

- Update `EntityUtils.java` or similar:
  - Remove JPA-specific exception imports (`ObjectRetrievalFailureException`)
  - Change method signatures from `int id` to `String id`
  - Update ID comparison logic: `entity.getId() == entityId` → `entity.getId().equals(entityId)`
  - Replace JPA exceptions with standard exceptions (`IllegalArgumentException`)

#### H. Update assertions for String IDs

- Change ID assertions:
  - `assertThat(entity.getId()).isNotZero()` → `assertThat(entity.getId()).isNotEmpty()`
  - `assertThat(entity.getId()).isEqualTo(1)` → `assertThat(entity.getId()).isEqualTo("test-id-1")`
  - JSON path assertions: `jsonPath("$.id").value(1)` → `jsonPath("$.id").value("test-id-1")`

### Step 8 — Test file conversion (CRITICAL SECTION)

**This step is often overlooked but essential for successful conversion**

#### A. **COMPILATION CHECK STRATEGY**

- **After each major change, run `mvn test-compile` to catch issues early**
- **Fix compilation errors systematically before proceeding**
- **Don't rely on IDE - Maven compilation reveals all issues**

#### B. **Search and Update ALL test files systematically**

**Use search tools to find and update every occurrence:**

- Search for: `setId\(\d+\)` → Replace with: `setId("test-id-X")`
- Search for: `findById\(\d+\)` → Replace with: `findById("test-id-X")`
- Search for: `\.findPetTypes\(\)` → Replace with: `.findAllOrderByName()`
- Search for: `\.findByLastNameStartingWith\(.*,.*Pageable` → Remove pagination parameter

#### C. Update test annotations and imports

- Replace `@DataJpaTest` with `@SpringBootTest` or appropriate slice test
- Remove `@AutoConfigureTestDatabase` annotations
- Remove `@Transactional` from tests (unless single-partition operations)
- Remove imports from `org.springframework.orm` package

#### D. Fix entity ID usage in ALL test files

**Critical files that MUST be updated (search entire test directory):**

- `*ControllerTests.java` - Path variables, entity creation, mock setup
- `*ServiceTests.java` - Repository interactions, entity IDs
- `EntityUtils.java` - Utility methods for ID handling
- `*FormatterTests.java` - Repository method calls
- `*ValidatorTests.java` - Entity creation with String IDs
- Integration test classes - Test data setup

#### E. **Fix Controller and Service classes affected by repository changes**

- **Update controllers that call repository methods with changed signatures**
- **Update formatters/converters that use repository methods**
- **Common files to check**:
  - `PetTypeFormatter.java` - often calls `findPetTypes()` method
  - `*Controller.java` - may have pagination logic to remove
  - Service classes that use repository methods

#### F. Update repository mocking in tests

- Remove pagination from repository mocks:
  - `given(repository.findByX(param, pageable)).willReturn(pageResult)`
  - → `given(repository.findByX(param)).willReturn(listResult)`
- Update method names in mocks:
  - `given(petTypeRepository.findPetTypes()).willReturn(types)`
  - → `given(petTypeRepository.findAllOrderByName()).willReturn(types)`

#### G. Fix utility classes used by tests

- Update `EntityUtils.java` or similar:
  - Remove JPA-specific exception imports (`ObjectRetrievalFailureException`)
  - Change method signatures from `int id` to `String id`
  - Update ID comparison logic: `entity.getId() == entityId` → `entity.getId().equals(entityId)`
  - Replace JPA exceptions with standard exceptions (`IllegalArgumentException`)

#### H. Update assertions for String IDs

- Change ID assertions:
  - `assertThat(entity.getId()).isNotZero()` → `assertThat(entity.getId()).isNotEmpty()`
  - `assertThat(entity.getId()).isEqualTo(1)` → `assertThat(entity.getId()).isEqualTo("test-id-1")`
  - JSON path assertions: `jsonPath("$.id").value(1)` → `jsonPath("$.id").value("test-id-1")`

### Step 9 — **Runtime Testing and Template Compatibility**

#### **CRITICAL**: Test the running application after compilation success

- **Start the application**: `mvn spring-boot:run`
- **Navigate through all pages** in the web interface to identify runtime errors
- **Common runtime issues after conversion**:
  - Templates trying to access properties that no longer exist (e.g., `vet.specialties`)
  - Service layer not populating transient relationship properties
  - Controllers not using service layer for relationship loading

#### **Template compatibility fixes**:

- **If templates access relationship properties** (e.g., `entity.relatedObjects`):
  - Ensure transient properties exist on entities with proper getters/setters
  - Verify service layer populates these transient properties
  - Update `getNrOfXXX()` methods to use transient lists instead of ID lists
- **Check for SpEL (Spring Expression Language) errors** in logs:
  - `Property or field 'xxx' cannot be found` → Add missing transient property
  - `EL1008E` errors → Service layer not populating relationships

#### **Service layer verification**:

- **Ensure all controllers use service layer** instead of direct repository access
- **Verify service methods populate relationships** before returning entities
- **Test all CRUD operations** through the web interface

### Step 9.5 — **Template Runtime Validation** (CRITICAL)

#### **Systematic Template Testing Process**

After successful compilation and application startup:

1. **Navigate to EVERY page** in the application systematically
2. **Test each template that displays entity data**:
   - List pages (e.g., `/vets`, `/owners`)
   - Detail pages (e.g., `/owners/{id}`, `/vets/{id}`)
   - Forms and edit pages
3. **Look for specific template errors**:
   - `Property or field 'relationshipName' cannot be found on object of type 'EntityName'`
   - `EL1008E` Spring Expression Language errors
   - Empty or missing data where relationships should appear

#### **Template Error Resolution Checklist**

When encountering template errors:

- [ ] **Identify the missing property** from error message
- [ ] **Check if property exists as transient field** in entity
- [ ] **Verify service layer populates the property** before returning entity
- [ ] **Ensure controller uses service layer**, not direct repository access
- [ ] **Test the specific page again** after fixes

#### **Common Template Error Patterns**

- `Property or field 'specialties' cannot be found` → Add `@JsonIgnore private List<Specialty> specialties` to Vet entity
- `Property or field 'pets' cannot be found` → Add `@JsonIgnore private List<Pet> pets` to Owner entity
- Empty relationship data displayed → Service not populating transient properties

### Step 10 — **Systematic Error Resolution Process**

#### When compilation fails:

1. **Run `mvn compile` first** - fix main source issues before tests
2. **Run `mvn test-compile`** - systematically fix each test compilation error
3. **Focus on most frequent error patterns**:
   - `int cannot be converted to String` → Change test constants and entity setters
   - `method X cannot be applied to given types` → Remove pagination parameters
   - `cannot find symbol: method Y()` → Update to new repository method names
   - Method signature conflicts → Rename conflicting methods

### Step 10 — **Systematic Error Resolution Process**

#### When compilation fails:

1. **Run `mvn compile` first** - fix main source issues before tests
2. **Run `mvn test-compile`** - systematically fix each test compilation error
3. **Focus on most frequent error patterns**:
   - `int cannot be converted to String` → Change test constants and entity setters
   - `method X cannot be applied to given types` → Remove pagination parameters
   - `cannot find symbol: method Y()` → Update to new repository method names
   - Method signature conflicts → Rename conflicting methods
#### When runtime fails:

1. **Check application logs** for specific error messages
2. **Look for template/SpEL errors**:
   - `Property or field 'xxx' cannot be found` → Add transient property to entity
   - Missing relationship data → Service layer not populating relationships
3. **Verify service layer usage** in controllers
4. **Test navigation through all application pages**

#### Common error patterns and solutions:

- **`method findByLastNameStartingWith cannot be applied`** → Remove `Pageable` parameter
- **`cannot find symbol: method findPetTypes()`** → Change to `findAllOrderByName()`
- **`incompatible types: int cannot be converted to String`** → Update test ID constants
- **`method getPet(String) is already defined`** → Rename one method (e.g., `getPetByName`)
- **`cannot find symbol: method isNotZero()`** → Change to `isNotEmpty()` for String IDs
- **`Property or field 'specialties' cannot be found`** → Add transient property and populate in service
- **`ClassCastException: reactor.core.publisher.BlockingIterable cannot be cast to java.util.List`** → Fix repository `findAllWithEagerRelationships()` method to use StreamSupport
- **`Unable to make field...BigDecimal.intVal accessible`** → Replace BigDecimal with Double throughout application
- **Health check database failure** → Remove 'db' from health check readiness configuration

#### **Template-Specific Runtime Errors**

- **`Property or field 'XXX' cannot be found on object of type 'YYY'`**:

  - Root cause: Template accessing relationship property that was converted to ID storage
  - Solution: Add transient property to entity + populate in service layer
  - Prevention: Always check template usage before converting relationships

- **`EL1008E` Spring Expression Language errors**:

  - Root cause: Service layer not populating transient properties
  - Solution: Verify `populateRelationships()` methods are called and working
  - Prevention: Test all template navigation after service layer implementation

- **Empty/null relationship data in templates**:
  - Root cause: Controller bypassing service layer or service not populating relationships
  - Solution: Ensure all controller methods use service layer for entity retrieval
  - Prevention: Never return repository results directly to templates

### Step 11 — Validation checklist

After conversion, verify:

- [ ] **Main application compiles**: `mvn compile` succeeds
- [ ] **All test files compile**: `mvn test-compile` succeeds
- [ ] **No compilation errors**: Address every single compilation error
- [ ] **Application starts successfully**: `mvn spring-boot:run` without errors
- [ ] **All web pages load**: Navigate through all application pages without runtime errors
- [ ] **Service layer populates relationships**: Transient properties are correctly set
- [ ] **All template pages render without errors**: Navigate through entire application
- [ ] **Relationship data displays correctly**: Lists, counts, and related objects show properly
- [ ] **No SpEL template errors in logs**: Check application logs during navigation
- [ ] **Transient properties are @JsonIgnore annotated**: Prevents JSON serialization issues
- [ ] **Service layer used consistently**: No direct repository access in controllers for template rendering
- [ ] No remaining `jakarta.persistence` imports
- [ ] All entity IDs are `String` type consistently
- [ ] All repository interfaces extend `CosmosRepository<Entity, String>`
- [ ] Configuration uses `DefaultAzureCredential` for authentication
- [ ] Data seeding component exists and works
- [ ] Test files use String IDs consistently
- [ ] Repository mocks updated for Cosmos methods
- [ ] **No method signature conflicts** in entity classes
- [ ] **All renamed methods updated** in callers (controllers, tests, formatters)

### Common pitfalls to avoid

1. **Not checking compilation frequently** - Run `mvn test-compile` after each major change
2. **Method signature conflicts** - Method overloading issues when converting ID types
3. **Forgetting to update method callers** - When renaming methods, update ALL callers
4. **Missing repository method renames** - Custom repository methods must be updated everywhere called
5. **Using key-based authentication** - Use `DefaultAzureCredential` instead
6. **Mixing Integer and String IDs** - Be consistent with String IDs everywhere, especially in tests
7. **Not updating controller pagination logic** - Remove pagination from controllers when repositories change
8. **Leaving JPA-specific test annotations** - Replace with Cosmos-compatible alternatives
9. **Incomplete test file updates** - Search entire test directory, not just obvious files
10. **Skipping runtime testing** - Always test the running application, not just compilation
11. **Missing service layer** - Don't access repositories directly from controllers
12. **Forgetting transient properties** - Templates may need access to relationship data
13. **Not testing template navigation** - Compilation success doesn't mean templates work
14. **Missing transient properties for templates** - Templates need object access, not just IDs
15. **Service layer bypassing** - Controllers must use services, never direct repository access
16. **Incomplete relationship population** - Service methods...

© github · MIT · github/awesome-copilot

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой