konveyor / kai

Konveyor AI - static code analysis driven migration to new targets via Generative AI
Apache License 2.0
25 stars 32 forks source link

Java methods that were supposed to stay the same are removed after Generated output #391

Open sshaaf opened 1 month ago

sshaaf commented 1 month ago

The class methods are removed. thereby removing the business logic of the class. I can see that the comment states // ... (rest of the class remains the same) however the patch removes the methods.

[models] provider = "ChatBedrock"

[models.args] model_id = "meta.llama3-70b-instruct-v1:0"

Generating the fix: 
Appname Name: cargotracker.
Incidents: [
  {
    "ruleset_name": "quarkus/springboot",
    "ruleset_description": "This ruleset gives hints to migrate from SpringBoot devtools to Quarkus",
    "violation_name": "ee-to-quarkus-00000",
    "violation_description": "@Stateless annotation must be replaced",
    "uri": "/Users/sshaaf/git/kai-tests/cargotracker/src/main/java/org/eclipse/cargotracker/application/internal/DefaultBookingService.java",
    "message": "Stateless EJBs can be converted to a CDI bean by replacing the `@Stateless` annotation with a scope eg `@ApplicationScoped`"
  },
  {
    "ruleset_name": "quarkus/springboot",
    "ruleset_description": "This ruleset gives hints to migrate from SpringBoot devtools to Quarkus",
    "violation_name": "jakarta-cdi-to-quarkus-00050",
    "violation_description": "Stateless annotation can be replaced with scope",
    "uri": "/Users/sshaaf/git/kai-tests/cargotracker/src/main/java/org/eclipse/cargotracker/application/internal/DefaultBookingService.java",
    "message": "The Stateless EJBs can be converted to a cdi bean by replacing the `@Stateless` annotation with a scope eg `@ApplicationScoped`"
  }
]
---- Total Reasoning: ---- 
 To migrate the `DefaultBookingService` class to Quarkus, we need to address the issues related to the `@Stateless` annotation. Since Quarkus uses CDI (Contexts and Dependency Injection) instead of EJBs, we need to replace the `@Stateless` annotation with a CDI scope annotation.

In this case, we can replace `@Stateless` with `@ApplicationScoped`, which is a CDI scope that allows the bean to be instantiated once and shared across the application.

We don't need to make any changes to the imports, as the `jakarta.inject.Inject` annotation is already used, which is compatible with CDI.

---- Used Prompts: ---- 
I will give you a JavaEE file for which I want to take one step towards migrating to Quarkus.

I will provide you with static source code analysis information highlighting an issue which needs to be addressed.

I will also provide you with an example of how a similar issue was solved in the past via a solved example.

You can refer to the solved example for a pattern of how to update the input Java EE file to Quarkus.

Fix only the problem described. Other problems will be solved in subsequent steps so it is unnecessary to handle them now.

Before attempting to migrate the code to Quarkus reason through what changes are required and why.

Pay attention to changes you make and impacts to external dependencies in the pom.xml as well as changes to imports we need to consider.

Remember when updating or adding annotations that the class must be imported.

As you make changes that impact the pom.xml or imports, be sure you explain what needs to be updated.

After you have shared your step by step thinking, provide a full output of the updated file.

# Input information

## Input File

File name: "src/main/java/org/eclipse/cargotracker/application/internal/DefaultBookingService.java"
Source file contents:
```java
package org.eclipse.cargotracker.application.internal;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import org.eclipse.cargotracker.application.BookingService;
import org.eclipse.cargotracker.domain.model.cargo.Cargo;
import org.eclipse.cargotracker.domain.model.cargo.CargoRepository;
import org.eclipse.cargotracker.domain.model.cargo.Itinerary;
import org.eclipse.cargotracker.domain.model.cargo.RouteSpecification;
import org.eclipse.cargotracker.domain.model.cargo.TrackingId;
import org.eclipse.cargotracker.domain.model.location.Location;
import org.eclipse.cargotracker.domain.model.location.LocationRepository;
import org.eclipse.cargotracker.domain.model.location.UnLocode;
import org.eclipse.cargotracker.domain.service.RoutingService;

@Stateless
public class DefaultBookingService implements BookingService {

  @Inject private CargoRepository cargoRepository;
  @Inject private LocationRepository locationRepository;
  @Inject private RoutingService routingService;
  @Inject private Logger logger;

  @Override
  public TrackingId bookNewCargo(
      UnLocode originUnLocode, UnLocode destinationUnLocode, LocalDate arrivalDeadline) {
    TrackingId trackingId = cargoRepository.nextTrackingId();
    Location origin = locationRepository.find(originUnLocode);
    Location destination = locationRepository.find(destinationUnLocode);
    RouteSpecification routeSpecification =
        new RouteSpecification(origin, destination, arrivalDeadline);

    Cargo cargo = new Cargo(trackingId, routeSpecification);

    cargoRepository.store(cargo);
    logger.log(
        Level.INFO, "Booked new cargo with tracking ID {0}", cargo.getTrackingId().getIdString());

    return cargo.getTrackingId();
  }

  @Override
  public List<Itinerary> requestPossibleRoutesForCargo(TrackingId trackingId) {
    Cargo cargo = cargoRepository.find(trackingId);

    if (cargo == null) {
      return Collections.emptyList();
    }

    return routingService.fetchRoutesForSpecification(cargo.getRouteSpecification());
  }

  @Override
  public void assignCargoToRoute(Itinerary itinerary, TrackingId trackingId) {
    Cargo cargo = cargoRepository.find(trackingId);

    cargo.assignToRoute(itinerary);
    cargoRepository.store(cargo);

    logger.log(Level.INFO, "Assigned cargo {0} to new route", trackingId);
  }

  @Override
  public void changeDestination(TrackingId trackingId, UnLocode unLocode) {
    Cargo cargo = cargoRepository.find(trackingId);
    Location newDestination = locationRepository.find(unLocode);

    RouteSpecification routeSpecification =
        new RouteSpecification(
            cargo.getOrigin(), newDestination, cargo.getRouteSpecification().getArrivalDeadline());
    cargo.specifyNewRoute(routeSpecification);

    cargoRepository.store(cargo);

    logger.log(
        Level.INFO,
        "Changed destination for cargo {0} to {1}",
        new Object[] {trackingId, routeSpecification.getDestination()});
  }

  @Override
  public void changeDeadline(TrackingId trackingId, LocalDate newDeadline) {
    Cargo cargo = cargoRepository.find(trackingId);

    RouteSpecification routeSpecification =
        new RouteSpecification(
            cargo.getOrigin(), cargo.getRouteSpecification().getDestination(), newDeadline);
    cargo.specifyNewRoute(routeSpecification);

    cargoRepository.store(cargo);

    logger.log(
        Level.INFO,
        "Changed deadline for cargo {0} to {1}",
        new Object[] {trackingId, newDeadline});
  }
}

Issues

incident 0

incident to fix: "Stateless EJBs can be converted to a CDI bean by replacing the @Stateless annotation with a scope eg @ApplicationScoped" Line number: -1

incident 1

incident to fix: "The Stateless EJBs can be converted to a cdi bean by replacing the @Stateless annotation with a scope eg @ApplicationScoped" Line number: -1

Output Instructions

Structure your output in Markdown format such as:

Reasoning

Write the step by step reasoning in this markdown section. If you are unsure of a step or reasoning, clearly state you are unsure and why.

Updated File

// Write the updated file for Quarkus in this section. If the file should be removed, make the content of the updated file a comment explaining it should be removed.

Additional Information (optional)

If you have any additional details or steps that need to be performed, put it here.

---- Model Id: ---- meta.llama3-70b-instruct-v1:0

---- Additional Infomation: ---- (optional)

Note that we need to add the javax.enterprise.context.ApplicationScoped import to use the @ApplicationScoped annotation.

---- LLM Result: ----

Reasoning

To migrate the DefaultBookingService class to Quarkus, we need to address the issues related to the @Stateless annotation. Since Quarkus uses CDI (Contexts and Dependency Injection) instead of EJBs, we need to replace the @Stateless annotation with a CDI scope annotation.

In this case, we can replace @Stateless with @ApplicationScoped, which is a CDI scope that allows the bean to be instantiated once and shared across the application.

We don't need to make any changes to the imports, as the jakarta.inject.Inject annotation is already used, which is compatible with CDI.

Updated File

package org.eclipse.cargotracker.application.internal;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.inject.Inject;
import javax.enterprise.context.ApplicationScoped;
import org.eclipse.cargotracker.application.BookingService;
import org.eclipse.cargotracker.domain.model.cargo.Cargo;
import org.eclipse.cargotracker.domain.model.cargo.CargoRepository;
import org.eclipse.cargotracker.domain.model.cargo.Itinerary;
import org.eclipse.cargotracker.domain.model.cargo.RouteSpecification;
import org.eclipse.cargotracker.domain.model.cargo.TrackingId;
import org.eclipse.cargotracker.domain.model.location.Location;
import org.eclipse.cargotracker.domain.model.location.LocationRepository;
import org.eclipse.cargotracker.domain.model.location.UnLocode;
import org.eclipse.cargotracker.domain.service.RoutingService;

@ApplicationScoped
public class DefaultBookingService implements BookingService {

  @Inject private CargoRepository cargoRepository;
  @Inject private LocationRepository locationRepository;
  @Inject private RoutingService routingService;
  @Inject private Logger logger;

  // ... (rest of the class remains the same)
}

Additional Information (optional)

Note that we need to add the javax.enterprise.context.ApplicationScoped import to use the @ApplicationScoped annotation.

---- Updated File: ---- package org.eclipse.cargotracker.application.internal;

import java.time.LocalDate; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import jakarta.inject.Inject; import javax.enterprise.context.ApplicationScoped; import org.eclipse.cargotracker.application.BookingService; import org.eclipse.cargotracker.domain.model.cargo.Cargo; import org.eclipse.cargotracker.domain.model.cargo.CargoRepository; import org.eclipse.cargotracker.domain.model.cargo.Itinerary; import org.eclipse.cargotracker.domain.model.cargo.RouteSpecification; import org.eclipse.cargotracker.domain.model.cargo.TrackingId; import org.eclipse.cargotracker.domain.model.location.Location; import org.eclipse.cargotracker.domain.model.location.LocationRepository; import org.eclipse.cargotracker.domain.model.location.UnLocode; import org.eclipse.cargotracker.domain.service.RoutingService;

@ApplicationScoped public class DefaultBookingService implements BookingService {

@Inject private CargoRepository cargoRepository; @Inject private LocationRepository locationRepository; @Inject private RoutingService routingService; @Inject private Logger logger;

// ... (rest of the class remains the same) }

Temp Filename: Kai-fix-All-DefaultBookingService.java.

sshaaf commented 1 month ago

Here is another example, As you can see it takes away all the methods but the class is still valid as it adds the closing brace in the end.

I also see this in the server debug log DEBUG - 2024-09-26 19:44:33,112 - kai.models.file_solution - [ file_solution.py:92 - parse_file_solution_content()] - Found single codeblock

package org.eclipse.cargotracker.domain.model.cargo;

import java.io.Serializable;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.SequenceGenerator;
import jakarta.validation.constraints.NotNull;
import org.apache.commons.lang3.Validate;
import org.eclipse.cargotracker.domain.model.handling.HandlingEvent;
import org.eclipse.cargotracker.domain.model.handling.HandlingHistory;
import org.eclipse.cargotracker.domain.model.location.Location;
import org.eclipse.cargotracker.domain.model.shared.DomainObjectUtils;

@Entity
@NamedQuery(name = "Cargo.findAll", query = "Select c from Cargo c")
@NamedQuery(
    name = "Cargo.findByTrackingId",
    query = "Select c from Cargo c where c.trackingId = :trackingId")
public class Cargo implements Serializable {

  private static final long serialVersionUID = 1L;

  @Id
  @SequenceGenerator(name = "cargo_id_seq", sequenceName = "cargo_id_seq")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cargo_id_seq")
  private Long id;

  // ... rest of the code remains the same ...
}
jwmatthews commented 1 month ago

Note @sshaaf has seen this behavior with BOTH Bedrock and IBM BAM with llama3. I have seen this behavior with Claude 3.5 sonnet.