Update dependencies, add character and scenario management features
- Upgrade Quarkus and OpenAPI generator versions in pom.xml. - Introduce CharacterService and ScenarioService for managing character and scenario templates. - Implement CharacterEntity and ScenarioEntity JPA entities with corresponding repositories. - Add RESTful APIs for listing and retrieving characters and scenarios. - Create JSON converter for persisting lists of strings in the database. - Update OpenAPI specification to include new endpoints for character and scenario management. - Add Liquibase migration scripts for character and scenario tables. - Configure application settings for Hibernate ORM and database generation.
This commit is contained in:
parent
cf93b35dd6
commit
3ce1215487
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.configuration.updateBuildConfiguration": "automatic"
|
||||
}
|
||||
20
pom.xml
20
pom.xml
@ -15,12 +15,14 @@
|
||||
<maven.surefire.plugin.version>3.2.5</maven.surefire.plugin.version>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.version>3.15.3</quarkus.platform.version>
|
||||
<quarkus.platform.version>3.31.2</quarkus.platform.version>
|
||||
<quarkus.plugin.version>${quarkus.platform.version}</quarkus.plugin.version>
|
||||
<jackson.version>2.20.1</jackson.version>
|
||||
<jackson.annotations.version>2.20</jackson.annotations.version>
|
||||
<lombok.version>1.18.42</lombok.version>
|
||||
<junit.jupiter.version>5.10.3</junit.jupiter.version>
|
||||
<mockito.version>5.12.0</mockito.version>
|
||||
<openapi.generator.version>7.11.0</openapi.generator.version>
|
||||
<openapi.generator.version>7.13.0</openapi.generator.version>
|
||||
<frontend.plugin.version>1.15.1</frontend.plugin.version>
|
||||
<node.version>v22.13.1</node.version>
|
||||
<npm.version>10.9.2</npm.version>
|
||||
@ -68,6 +70,10 @@
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-liquibase</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-hibernate-orm-panache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-rest-client-config</artifactId>
|
||||
@ -135,6 +141,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- On Java 25, skip to avoid VerifyError; run JAVA_HOME=/path/to/jdk21 mvn generate-sources first. -->
|
||||
<plugin>
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-maven-plugin</artifactId>
|
||||
@ -148,6 +155,7 @@
|
||||
<configuration>
|
||||
<inputSpec>${project.basedir}/src/main/resources/openapi-roleplay-public-v1.yml</inputSpec>
|
||||
<generatorName>jaxrs-spec</generatorName>
|
||||
<templateDirectory>${project.basedir}/src/main/resources/openapi-templates</templateDirectory>
|
||||
<output>${project.build.directory}/generated-sources/openapi</output>
|
||||
<apiPackage>de.neitzel.roleplay.generated.api</apiPackage>
|
||||
<modelPackage>de.neitzel.roleplay.fascade.model</modelPackage>
|
||||
@ -172,6 +180,7 @@
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<skip>${skip.openapi.generate}</skip>
|
||||
<inputSpec>${project.basedir}/src/main/resources/openapi-roleplay-public-v1.yml</inputSpec>
|
||||
<generatorName>typescript-fetch</generatorName>
|
||||
<output>${project.basedir}/src/main/web/src/api/generated</output>
|
||||
@ -207,8 +216,11 @@
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven.surefire.plugin.version}</version>
|
||||
<configuration>
|
||||
<useModulePath>false</useModulePath>
|
||||
<argLine>-Dnet.bytebuddy.experimental=true</argLine>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
package de.neitzel.roleplay.business;
|
||||
|
||||
import de.neitzel.roleplay.data.CharacterEntity;
|
||||
import de.neitzel.roleplay.data.CharacterRepository;
|
||||
import de.neitzel.roleplay.fascade.model.CharacterDefinition;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Business service for stored character templates. Maps entities to API DTOs.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class CharacterService {
|
||||
|
||||
private final CharacterRepository characterRepository;
|
||||
|
||||
@Inject
|
||||
public CharacterService(final CharacterRepository characterRepository) {
|
||||
this.characterRepository = characterRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all stored characters as API definitions.
|
||||
*
|
||||
* @return list of character definitions, ordered by name
|
||||
*/
|
||||
public List<CharacterDefinition> listCharacters() {
|
||||
return characterRepository.listAll().stream()
|
||||
.map(CharacterService::toCharacterDefinition)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single character by id, if present.
|
||||
*
|
||||
* @param id the character UUID
|
||||
* @return the character definition or empty
|
||||
*/
|
||||
public Optional<CharacterDefinition> getCharacter(final UUID id) {
|
||||
CharacterEntity entity = characterRepository.findByIdOptional(id);
|
||||
return entity != null ? Optional.of(toCharacterDefinition(entity)) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a character entity to the API CharacterDefinition. Uses entity id as string for API id.
|
||||
*/
|
||||
public static CharacterDefinition toCharacterDefinition(final CharacterEntity entity) {
|
||||
CharacterDefinition def = new CharacterDefinition(
|
||||
entity.getId().toString(),
|
||||
entity.getName(),
|
||||
entity.getRole()
|
||||
);
|
||||
def.setBackstory(entity.getBackstory());
|
||||
def.setSpeakingStyle(entity.getSpeakingStyle());
|
||||
if (entity.getPersonalityTraits() != null && !entity.getPersonalityTraits().isEmpty()) {
|
||||
def.setPersonalityTraits(entity.getPersonalityTraits());
|
||||
}
|
||||
if (entity.getGoals() != null && !entity.getGoals().isEmpty()) {
|
||||
def.setGoals(entity.getGoals());
|
||||
}
|
||||
return def;
|
||||
}
|
||||
}
|
||||
@ -36,6 +36,7 @@ public class InMemorySessionService implements SessionService {
|
||||
|
||||
private final OllamaClient ollamaClient;
|
||||
private final com.fasterxml.jackson.databind.ObjectMapper objectMapper;
|
||||
private final ScenarioService scenarioService;
|
||||
|
||||
/**
|
||||
* In-memory store mapping session IDs to their current state.
|
||||
@ -47,12 +48,15 @@ public class InMemorySessionService implements SessionService {
|
||||
*
|
||||
* @param ollamaClient client for Ollama narrative and state-update calls
|
||||
* @param objectMapper mapper to serialize turn context to JSON
|
||||
* @param scenarioService service to resolve scenario by id from the database
|
||||
*/
|
||||
@Inject
|
||||
public InMemorySessionService(final OllamaClient ollamaClient,
|
||||
final com.fasterxml.jackson.databind.ObjectMapper objectMapper) {
|
||||
final com.fasterxml.jackson.databind.ObjectMapper objectMapper,
|
||||
final ScenarioService scenarioService) {
|
||||
this.ollamaClient = ollamaClient;
|
||||
this.objectMapper = objectMapper;
|
||||
this.scenarioService = scenarioService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,11 +81,12 @@ public class InMemorySessionService implements SessionService {
|
||||
0
|
||||
);
|
||||
|
||||
if (request.getScenario() != null) {
|
||||
session.setSituation(buildSituationFromScenario(request.getScenario()));
|
||||
session.setCharacters(buildCharactersFromScenario(request.getScenario()));
|
||||
ScenarioSetup scenario = resolveScenario(request);
|
||||
if (scenario != null) {
|
||||
session.setSituation(buildSituationFromScenario(scenario));
|
||||
session.setCharacters(buildCharactersFromScenario(scenario));
|
||||
try {
|
||||
String contextJson = objectMapper.writeValueAsString(OllamaContextBuilder.fromScenario(request.getScenario()));
|
||||
String contextJson = objectMapper.writeValueAsString(OllamaContextBuilder.fromScenario(scenario));
|
||||
String narrative = ollamaClient.generateNarrative(model, OllamaPrompts.INIT_NARRATIVE, contextJson);
|
||||
String userContentForCall2 = contextJson + "\n\nNarrative that was just generated:\n" + narrative;
|
||||
StateUpdateResponse stateUpdate = ollamaClient.generateStateUpdate(model, OllamaPrompts.STATE_EXTRACTION, userContentForCall2);
|
||||
@ -98,6 +103,19 @@ public class InMemorySessionService implements SessionService {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the effective scenario: scenarioId from DB takes precedence over inline scenario.
|
||||
*
|
||||
* @param request the create session request
|
||||
* @return the scenario to use, or null if none
|
||||
*/
|
||||
private ScenarioSetup resolveScenario(final CreateSessionRequest request) {
|
||||
if (request.getScenarioId() != null) {
|
||||
return scenarioService.getScenarioAsSetup(request.getScenarioId()).orElse(null);
|
||||
}
|
||||
return request.getScenario();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds initial situation state from the scenario setup.
|
||||
*
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
package de.neitzel.roleplay.business;
|
||||
|
||||
import de.neitzel.roleplay.data.ScenarioCharacterEntity;
|
||||
import de.neitzel.roleplay.data.ScenarioEntity;
|
||||
import de.neitzel.roleplay.data.ScenarioRepository;
|
||||
import de.neitzel.roleplay.fascade.model.CharacterDefinition;
|
||||
import de.neitzel.roleplay.fascade.model.ScenarioSetup;
|
||||
import de.neitzel.roleplay.fascade.model.ScenarioSummary;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Business service for stored scenario templates. Maps entities to API DTOs.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class ScenarioService {
|
||||
|
||||
private final ScenarioRepository scenarioRepository;
|
||||
|
||||
@Inject
|
||||
public ScenarioService(final ScenarioRepository scenarioRepository) {
|
||||
this.scenarioRepository = scenarioRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all stored scenarios as summaries.
|
||||
*
|
||||
* @return list of scenario summaries
|
||||
*/
|
||||
public List<ScenarioSummary> listScenarios() {
|
||||
return scenarioRepository.listAll().stream()
|
||||
.map(ScenarioService::toScenarioSummary)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full scenario setup for the given id, if present.
|
||||
*
|
||||
* @param id the scenario UUID
|
||||
* @return the scenario setup (setting, conflict, user character, AI characters) or empty
|
||||
*/
|
||||
public Optional<ScenarioSetup> getScenarioAsSetup(final UUID id) {
|
||||
ScenarioEntity entity = scenarioRepository.findByIdWithCharacters(id);
|
||||
return entity != null ? Optional.of(toScenarioSetup(entity)) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a scenario entity to the list-summary DTO.
|
||||
*/
|
||||
public static ScenarioSummary toScenarioSummary(final ScenarioEntity entity) {
|
||||
ScenarioSummary summary = new ScenarioSummary(entity.getId(), entity.getName());
|
||||
summary.setSetting(entity.getSetting());
|
||||
summary.setInitialConflict(entity.getInitialConflict());
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a scenario entity (with characters loaded) to the full ScenarioSetup for session creation.
|
||||
*/
|
||||
public static ScenarioSetup toScenarioSetup(final ScenarioEntity entity) {
|
||||
ScenarioSetup setup = new ScenarioSetup();
|
||||
setup.setSetting(entity.getSetting());
|
||||
setup.setInitialConflict(entity.getInitialConflict());
|
||||
List<ScenarioCharacterEntity> links = entity.getScenarioCharacters();
|
||||
if (links != null && !links.isEmpty()) {
|
||||
for (ScenarioCharacterEntity link : links) {
|
||||
CharacterDefinition def = CharacterService.toCharacterDefinition(link.getCharacter());
|
||||
if (link.isUserCharacter()) {
|
||||
setup.setUserCharacter(def);
|
||||
} else {
|
||||
setup.addAiCharactersItem(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
return setup;
|
||||
}
|
||||
}
|
||||
148
src/main/java/de/neitzel/roleplay/data/CharacterEntity.java
Normal file
148
src/main/java/de/neitzel/roleplay/data/CharacterEntity.java
Normal file
@ -0,0 +1,148 @@
|
||||
package de.neitzel.roleplay.data;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JPA entity for a reusable character definition stored in {@code rp_character}.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "rp_character")
|
||||
public class CharacterEntity extends PanacheEntityBase {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", length = 36, nullable = false, updatable = false)
|
||||
private UUID id;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 255)
|
||||
private String name;
|
||||
|
||||
@Column(name = "role", nullable = false, length = 255)
|
||||
private String role;
|
||||
|
||||
@Column(name = "backstory", columnDefinition = "clob")
|
||||
private String backstory;
|
||||
|
||||
@Convert(converter = JsonListStringConverter.class)
|
||||
@Column(name = "personality_traits", columnDefinition = "clob")
|
||||
private List<String> personalityTraits;
|
||||
|
||||
@Column(name = "speaking_style", length = 1000)
|
||||
private String speakingStyle;
|
||||
|
||||
@Convert(converter = JsonListStringConverter.class)
|
||||
@Column(name = "goals", columnDefinition = "clob")
|
||||
private List<String> goals;
|
||||
|
||||
/**
|
||||
* Default constructor for JPA.
|
||||
*/
|
||||
public CharacterEntity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of this character.
|
||||
*/
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of this character.
|
||||
*/
|
||||
public void setId(final UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display name of this character.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display name of this character.
|
||||
*/
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the narrative role of this character.
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the narrative role of this character.
|
||||
*/
|
||||
public void setRole(final String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the backstory text, or null if not set.
|
||||
*/
|
||||
public String getBackstory() {
|
||||
return backstory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backstory text.
|
||||
*/
|
||||
public void setBackstory(final String backstory) {
|
||||
this.backstory = backstory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of personality trait strings; never null.
|
||||
*/
|
||||
public List<String> getPersonalityTraits() {
|
||||
return personalityTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of personality trait strings.
|
||||
*/
|
||||
public void setPersonalityTraits(final List<String> personalityTraits) {
|
||||
this.personalityTraits = personalityTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the speaking style description, or null if not set.
|
||||
*/
|
||||
public String getSpeakingStyle() {
|
||||
return speakingStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speaking style description.
|
||||
*/
|
||||
public void setSpeakingStyle(final String speakingStyle) {
|
||||
this.speakingStyle = speakingStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of goal strings; never null.
|
||||
*/
|
||||
public List<String> getGoals() {
|
||||
return goals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of goal strings.
|
||||
*/
|
||||
public void setGoals(final List<String> goals) {
|
||||
this.goals = goals;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package de.neitzel.roleplay.data;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Panache repository for {@link CharacterEntity}. Provides list-all and find-by-id access.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class CharacterRepository implements PanacheRepository<CharacterEntity> {
|
||||
|
||||
/**
|
||||
* Returns all characters ordered by name.
|
||||
*/
|
||||
@Override
|
||||
public List<CharacterEntity> listAll() {
|
||||
return list("ORDER BY name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a character by its UUID.
|
||||
*
|
||||
* @param id the character id
|
||||
* @return the entity or null if not found
|
||||
*/
|
||||
public CharacterEntity findByIdOptional(final UUID id) {
|
||||
return find("id", id).firstResult();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package de.neitzel.roleplay.data;
|
||||
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Converter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* JPA converter that persists a {@link List} of {@link String} as JSON in a CLOB column.
|
||||
*/
|
||||
@Converter
|
||||
public class JsonListStringConverter implements AttributeConverter<List<String>, String> {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final TypeReference<List<String>> LIST_TYPE = new TypeReference<>() {};
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(final List<String> attribute) {
|
||||
if (attribute == null || attribute.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return MAPPER.writeValueAsString(attribute);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to serialize string list to JSON", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> convertToEntityAttribute(final String dbData) {
|
||||
if (dbData == null || dbData.isBlank()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try {
|
||||
return MAPPER.readValue(dbData, LIST_TYPE);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to deserialize JSON to string list", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
package de.neitzel.roleplay.data;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Join entity linking a scenario to a character with role (user vs AI) and ordering.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "scenario_character")
|
||||
public class ScenarioCharacterEntity extends PanacheEntityBase {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", length = 36, nullable = false, updatable = false)
|
||||
private UUID id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "scenario_id", nullable = false)
|
||||
private ScenarioEntity scenario;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "character_id", nullable = false)
|
||||
private CharacterEntity character;
|
||||
|
||||
@Column(name = "is_user_character", nullable = false)
|
||||
private boolean userCharacter;
|
||||
|
||||
@Column(name = "position", nullable = false)
|
||||
private int position;
|
||||
|
||||
/**
|
||||
* Default constructor for JPA.
|
||||
*/
|
||||
public ScenarioCharacterEntity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of this link.
|
||||
*/
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of this link.
|
||||
*/
|
||||
public void setId(final UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scenario this link belongs to.
|
||||
*/
|
||||
public ScenarioEntity getScenario() {
|
||||
return scenario;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scenario this link belongs to.
|
||||
*/
|
||||
public void setScenario(final ScenarioEntity scenario) {
|
||||
this.scenario = scenario;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character referenced by this link.
|
||||
*/
|
||||
public CharacterEntity getCharacter() {
|
||||
return character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the character referenced by this link.
|
||||
*/
|
||||
public void setCharacter(final CharacterEntity character) {
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this slot is the user-controlled character.
|
||||
*/
|
||||
public boolean isUserCharacter() {
|
||||
return userCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this slot is the user-controlled character.
|
||||
*/
|
||||
public void setUserCharacter(final boolean userCharacter) {
|
||||
this.userCharacter = userCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position for ordering (e.g. AI characters).
|
||||
*/
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position for ordering.
|
||||
*/
|
||||
public void setPosition(final int position) {
|
||||
this.position = position;
|
||||
}
|
||||
}
|
||||
116
src/main/java/de/neitzel/roleplay/data/ScenarioEntity.java
Normal file
116
src/main/java/de/neitzel/roleplay/data/ScenarioEntity.java
Normal file
@ -0,0 +1,116 @@
|
||||
package de.neitzel.roleplay.data;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderBy;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JPA entity for a scenario template stored in {@code scenario}.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "scenario")
|
||||
public class ScenarioEntity extends PanacheEntityBase {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", length = 36, nullable = false, updatable = false)
|
||||
private UUID id;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 255)
|
||||
private String name;
|
||||
|
||||
@Column(name = "setting", columnDefinition = "clob")
|
||||
private String setting;
|
||||
|
||||
@Column(name = "initial_conflict", columnDefinition = "clob")
|
||||
private String initialConflict;
|
||||
|
||||
@OneToMany(mappedBy = "scenario", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@OrderBy("isUserCharacter DESC, position ASC")
|
||||
private List<ScenarioCharacterEntity> scenarioCharacters = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Default constructor for JPA.
|
||||
*/
|
||||
public ScenarioEntity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of this scenario.
|
||||
*/
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of this scenario.
|
||||
*/
|
||||
public void setId(final UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable name of this scenario.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the human-readable name of this scenario.
|
||||
*/
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting description (place, time, atmosphere), or null if not set.
|
||||
*/
|
||||
public String getSetting() {
|
||||
return setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setting description.
|
||||
*/
|
||||
public void setSetting(final String setting) {
|
||||
this.setting = setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial conflict text, or null if not set.
|
||||
*/
|
||||
public String getInitialConflict() {
|
||||
return initialConflict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial conflict text.
|
||||
*/
|
||||
public void setInitialConflict(final String initialConflict) {
|
||||
this.initialConflict = initialConflict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of scenario–character links (user character first, then AI by position).
|
||||
*/
|
||||
public List<ScenarioCharacterEntity> getScenarioCharacters() {
|
||||
return scenarioCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of scenario–character links.
|
||||
*/
|
||||
public void setScenarioCharacters(final List<ScenarioCharacterEntity> scenarioCharacters) {
|
||||
this.scenarioCharacters = scenarioCharacters;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package de.neitzel.roleplay.data;
|
||||
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Panache repository for {@link ScenarioEntity}. Provides list-all and find-by-id with characters loaded.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class ScenarioRepository implements PanacheRepository<ScenarioEntity> {
|
||||
|
||||
/**
|
||||
* Finds a scenario by its UUID and loads its scenario-character links and linked characters.
|
||||
*
|
||||
* @param id the scenario id
|
||||
* @return the entity or null if not found
|
||||
*/
|
||||
public ScenarioEntity findByIdWithCharacters(final UUID id) {
|
||||
ScenarioEntity scenario = find("id", id).firstResult();
|
||||
if (scenario != null) {
|
||||
scenario.getScenarioCharacters().size();
|
||||
scenario.getScenarioCharacters().forEach(sc -> sc.getCharacter().getName());
|
||||
}
|
||||
return scenario;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all scenarios ordered by name.
|
||||
*/
|
||||
@Override
|
||||
public List<ScenarioEntity> listAll() {
|
||||
return list("ORDER BY name");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package de.neitzel.roleplay.fascade;
|
||||
|
||||
import de.neitzel.roleplay.business.CharacterService;
|
||||
import de.neitzel.roleplay.fascade.model.CharacterDefinition;
|
||||
import de.neitzel.roleplay.fascade.model.CharacterListResponse;
|
||||
import de.neitzel.roleplay.generated.api.CharactersApi;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JAX-RS resource that implements the {@link CharactersApi} interface generated from the OpenAPI spec.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class CharactersResource implements CharactersApi {
|
||||
|
||||
private final CharacterService characterService;
|
||||
|
||||
@Inject
|
||||
public CharactersResource(final CharacterService characterService) {
|
||||
this.characterService = characterService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharacterListResponse listCharacters() {
|
||||
CharacterListResponse response = new CharacterListResponse();
|
||||
response.setCharacters(characterService.listCharacters());
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharacterDefinition getCharacter(final UUID characterId) {
|
||||
return characterService.getCharacter(characterId)
|
||||
.orElseThrow(() -> new NotFoundException("No character found with id: " + characterId));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package de.neitzel.roleplay.fascade;
|
||||
|
||||
import de.neitzel.roleplay.business.ScenarioService;
|
||||
import de.neitzel.roleplay.fascade.model.ScenarioListResponse;
|
||||
import de.neitzel.roleplay.fascade.model.ScenarioSetup;
|
||||
import de.neitzel.roleplay.generated.api.ScenariosApi;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JAX-RS resource that implements the {@link ScenariosApi} interface generated from the OpenAPI spec.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class ScenariosResource implements ScenariosApi {
|
||||
|
||||
private final ScenarioService scenarioService;
|
||||
|
||||
@Inject
|
||||
public ScenariosResource(final ScenarioService scenarioService) {
|
||||
this.scenarioService = scenarioService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScenarioListResponse listScenarios() {
|
||||
ScenarioListResponse response = new ScenarioListResponse();
|
||||
response.setScenarios(scenarioService.listScenarios());
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScenarioSetup getScenario(final UUID scenarioId) {
|
||||
return scenarioService.getScenarioAsSetup(scenarioId)
|
||||
.orElseThrow(() -> new NotFoundException("No scenario found with id: " + scenarioId));
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,9 @@ quarkus:
|
||||
url: jdbc:h2:mem:roleplay;DB_CLOSE_DELAY=-1
|
||||
username: sa
|
||||
password: ""
|
||||
hibernate-orm:
|
||||
database:
|
||||
generation: none
|
||||
liquibase:
|
||||
change-log: db/migration/changelog.xml
|
||||
migrate-at-start: true
|
||||
|
||||
@ -4,5 +4,7 @@
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
|
||||
|
||||
<include file="db/migration/v001__scenarios_and_characters.xml"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.24.xsd">
|
||||
|
||||
<changeSet id="001-1-create-character-table" author="roleplay">
|
||||
<createTable tableName="rp_character">
|
||||
<column name="id" type="uuid">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="name" type="varchar(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="role" type="varchar(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="backstory" type="clob"/>
|
||||
<column name="personality_traits" type="clob"/>
|
||||
<column name="speaking_style" type="varchar(1000)"/>
|
||||
<column name="goals" type="clob"/>
|
||||
</createTable>
|
||||
<comment>Stores reusable character definitions. personality_traits and goals stored as JSON text.</comment>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="001-2-create-scenario-table" author="roleplay">
|
||||
<createTable tableName="scenario">
|
||||
<column name="id" type="uuid">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="name" type="varchar(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="setting" type="clob"/>
|
||||
<column name="initial_conflict" type="clob"/>
|
||||
</createTable>
|
||||
<comment>Stores scenario templates (setting and initial conflict).</comment>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="001-3-create-scenario-character-table" author="roleplay">
|
||||
<createTable tableName="scenario_character">
|
||||
<column name="id" type="uuid">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="scenario_id" type="uuid">
|
||||
<constraints nullable="false" foreignKeyName="fk_scenario_character_scenario"
|
||||
references="scenario(id)"/>
|
||||
</column>
|
||||
<column name="character_id" type="uuid">
|
||||
<constraints nullable="false" foreignKeyName="fk_scenario_character_character"
|
||||
references="rp_character(id)"/>
|
||||
</column>
|
||||
<column name="is_user_character" type="boolean">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="position" type="int">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<comment>Links scenarios to characters; position orders AI characters.</comment>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="001-4-seed-example-scenario" author="roleplay">
|
||||
<insert tableName="rp_character">
|
||||
<column name="id" value="11111111-1111-1111-1111-111111111101"/>
|
||||
<column name="name" value="The Detective"/>
|
||||
<column name="role" value="rookie detective"/>
|
||||
<column name="backstory" value="Recently joined the force, eager to prove themselves."/>
|
||||
<column name="personality_traits" value="["curious", "determined"]"/>
|
||||
<column name="goals" value="["Solve the case", "Earn respect"]"/>
|
||||
</insert>
|
||||
<insert tableName="rp_character">
|
||||
<column name="id" value="11111111-1111-1111-1111-111111111102"/>
|
||||
<column name="name" value="Captain Morgan"/>
|
||||
<column name="role" value="ship captain"/>
|
||||
<column name="backstory" value="Veteran of many voyages; hides a secret."/>
|
||||
<column name="personality_traits" value="["gruff", "wary"]"/>
|
||||
<column name="goals" value="["Protect the crew", "Keep the past buried"]"/>
|
||||
</insert>
|
||||
<insert tableName="scenario">
|
||||
<column name="id" value="22222222-2222-2222-2222-222222222201"/>
|
||||
<column name="name" value="Harbour mystery"/>
|
||||
<column name="setting" value="A fog-covered harbour at dawn, 1923"/>
|
||||
<column name="initial_conflict" value="Strange noises from the cargo hold"/>
|
||||
</insert>
|
||||
<insert tableName="scenario_character">
|
||||
<column name="id" value="33333333-3333-3333-3333-333333333301"/>
|
||||
<column name="scenario_id" value="22222222-2222-2222-2222-222222222201"/>
|
||||
<column name="character_id" value="11111111-1111-1111-1111-111111111101"/>
|
||||
<column name="is_user_character" valueBoolean="true"/>
|
||||
<column name="position" valueNumeric="0"/>
|
||||
</insert>
|
||||
<insert tableName="scenario_character">
|
||||
<column name="id" value="33333333-3333-3333-3333-333333333302"/>
|
||||
<column name="scenario_id" value="22222222-2222-2222-2222-222222222201"/>
|
||||
<column name="character_id" value="11111111-1111-1111-1111-111111111102"/>
|
||||
<column name="is_user_character" valueBoolean="false"/>
|
||||
<column name="position" valueNumeric="1"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@ -19,6 +19,10 @@ tags:
|
||||
description: Manage role-play sessions
|
||||
- name: turns
|
||||
description: Submit user actions within a session
|
||||
- name: scenarios
|
||||
description: List and retrieve saved scenario templates
|
||||
- name: characters
|
||||
description: List and retrieve saved character templates
|
||||
|
||||
paths:
|
||||
|
||||
@ -43,6 +47,82 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/scenarios:
|
||||
get:
|
||||
operationId: listScenarios
|
||||
summary: List saved scenarios
|
||||
description: Returns all stored scenario templates for selection when starting a session.
|
||||
tags:
|
||||
- scenarios
|
||||
responses:
|
||||
"200":
|
||||
description: List of scenario summaries.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScenarioListResponse'
|
||||
|
||||
/scenarios/{scenarioId}:
|
||||
get:
|
||||
operationId: getScenario
|
||||
summary: Get a scenario by id
|
||||
description: Returns the full scenario setup (setting, conflict, characters) for the given id.
|
||||
tags:
|
||||
- scenarios
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/ScenarioId'
|
||||
responses:
|
||||
"200":
|
||||
description: Scenario found and returned.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ScenarioSetup'
|
||||
"404":
|
||||
description: Scenario not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/characters:
|
||||
get:
|
||||
operationId: listCharacters
|
||||
summary: List saved characters
|
||||
description: Returns all stored character templates for selection when building a scenario.
|
||||
tags:
|
||||
- characters
|
||||
responses:
|
||||
"200":
|
||||
description: List of character definitions.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CharacterListResponse'
|
||||
|
||||
/characters/{characterId}:
|
||||
get:
|
||||
operationId: getCharacter
|
||||
summary: Get a character by id
|
||||
description: Returns the full character definition for the given id.
|
||||
tags:
|
||||
- characters
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/CharacterId'
|
||||
responses:
|
||||
"200":
|
||||
description: Character found and returned.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CharacterDefinition'
|
||||
"404":
|
||||
description: Character not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/sessions:
|
||||
post:
|
||||
operationId: createSession
|
||||
@ -191,6 +271,22 @@ components:
|
||||
description: Unique identifier of the role-play session.
|
||||
schema:
|
||||
type: string
|
||||
ScenarioId:
|
||||
name: scenarioId
|
||||
in: path
|
||||
required: true
|
||||
description: Unique identifier of the scenario (UUID).
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
CharacterId:
|
||||
name: characterId
|
||||
in: path
|
||||
required: true
|
||||
description: Unique identifier of the character (UUID).
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
|
||||
schemas:
|
||||
|
||||
@ -255,9 +351,56 @@ components:
|
||||
default: standard
|
||||
scenario:
|
||||
$ref: '#/components/schemas/ScenarioSetup'
|
||||
scenarioId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: If set, the backend loads this scenario from the database and uses it instead of an inline scenario.
|
||||
required:
|
||||
- model
|
||||
|
||||
ScenarioSummary:
|
||||
type: object
|
||||
description: Summary of a stored scenario for list views.
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the scenario.
|
||||
name:
|
||||
type: string
|
||||
description: Human-readable scenario name.
|
||||
setting:
|
||||
type: string
|
||||
description: Place, time, and atmosphere (optional in list).
|
||||
initialConflict:
|
||||
type: string
|
||||
description: The hook or starting conflict (optional in list).
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
|
||||
ScenarioListResponse:
|
||||
type: object
|
||||
description: Response containing all stored scenarios.
|
||||
properties:
|
||||
scenarios:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ScenarioSummary'
|
||||
required:
|
||||
- scenarios
|
||||
|
||||
CharacterListResponse:
|
||||
type: object
|
||||
description: Response containing all stored characters.
|
||||
properties:
|
||||
characters:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/CharacterDefinition'
|
||||
required:
|
||||
- characters
|
||||
|
||||
ScenarioSetup:
|
||||
type: object
|
||||
description: |
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
{{#required}}
|
||||
{{^isReadOnly}}
|
||||
@NotNull
|
||||
{{/isReadOnly}}
|
||||
{{/required}}
|
||||
{{#isContainer}}
|
||||
{{! Do not add @Valid on container; we use type-argument @Valid in the pojo (List<@Valid T>) to fix HV000271 }}
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
{{^isPrimitiveType}}
|
||||
@Valid
|
||||
{{/isPrimitiveType}}
|
||||
{{/isContainer}}
|
||||
{{>beanValidationCore}}
|
||||
@ -0,0 +1,14 @@
|
||||
{{#required}}
|
||||
{{^isReadOnly}}
|
||||
@NotNull
|
||||
{{/isReadOnly}}
|
||||
{{/required}}
|
||||
{{#isContainer}}
|
||||
{{! Do not add @Valid on container; we use type-argument @Valid in the pojo (List<@Valid T>) to fix HV000271 }}
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
{{^isPrimitiveType}}
|
||||
@Valid
|
||||
{{/isPrimitiveType}}
|
||||
{{/isContainer}}
|
||||
{{>beanValidationCore}}
|
||||
146
src/main/resources/openapi-templates/JavaJaxRS/pojo.mustache
Normal file
146
src/main/resources/openapi-templates/JavaJaxRS/pojo.mustache
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* {{description}}{{^description}}{{classname}}{{/description}}
|
||||
*/{{#description}}
|
||||
@ApiModel(description = "{{{.}}}"){{/description}}
|
||||
{{#jackson}}
|
||||
@JsonPropertyOrder({
|
||||
{{#vars}}
|
||||
{{classname}}.JSON_PROPERTY_{{nameInSnakeCase}}{{^-last}},{{/-last}}
|
||||
{{/vars}}
|
||||
})
|
||||
{{/jackson}}
|
||||
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}
|
||||
{{#vendorExtensions.x-class-extra-annotation}}
|
||||
{{{vendorExtensions.x-class-extra-annotation}}}
|
||||
{{/vendorExtensions.x-class-extra-annotation}}
|
||||
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
{{^isContainer}}
|
||||
{{>enumClass}}
|
||||
|
||||
{{/isContainer}}
|
||||
{{#isContainer}}
|
||||
{{#mostInnerItems}}
|
||||
{{>enumClass}}
|
||||
|
||||
{{/mostInnerItems}}
|
||||
{{/isContainer}}
|
||||
{{/isEnum}}
|
||||
{{#jackson}}
|
||||
public static final String JSON_PROPERTY_{{nameInSnakeCase}} = "{{baseName}}";
|
||||
@JsonProperty(JSON_PROPERTY_{{nameInSnakeCase}})
|
||||
{{/jackson}}
|
||||
{{#gson}}
|
||||
public static final String SERIALIZED_NAME_{{nameInSnakeCase}} = "{{baseName}}";
|
||||
@SerializedName(SERIALIZED_NAME_{{nameInSnakeCase}})
|
||||
{{/gson}}
|
||||
{{#vendorExtensions.x-field-extra-annotation}}
|
||||
{{{.}}}
|
||||
{{/vendorExtensions.x-field-extra-annotation}}
|
||||
private {{>propertyType}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
|
||||
|
||||
{{/vars}}
|
||||
{{#vars}}
|
||||
public {{classname}} {{name}}({{>propertyType}} {{name}}) {
|
||||
this.{{name}} = {{name}};
|
||||
return this;
|
||||
}
|
||||
{{#isArray}}
|
||||
|
||||
public {{classname}} add{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if (this.{{name}} == null) {
|
||||
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
|
||||
}
|
||||
this.{{name}}.add({{name}}Item);
|
||||
return this;
|
||||
}
|
||||
{{/isArray}}
|
||||
{{#isMap}}
|
||||
|
||||
public {{classname}} put{{nameInPascalCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if (this.{{name}} == null) {
|
||||
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
|
||||
}
|
||||
this.{{name}}.put(key, {{name}}Item);
|
||||
return this;
|
||||
}
|
||||
{{/isMap}}
|
||||
|
||||
/**
|
||||
{{#description}}
|
||||
* {{.}}
|
||||
{{/description}}
|
||||
{{^description}}
|
||||
* Get {{name}}
|
||||
{{/description}}
|
||||
{{#minimum}}
|
||||
* minimum: {{.}}
|
||||
{{/minimum}}
|
||||
{{#maximum}}
|
||||
* maximum: {{.}}
|
||||
{{/maximum}}
|
||||
* @return {{name}}
|
||||
**/
|
||||
{{#vendorExtensions.x-extra-annotation}}
|
||||
{{{vendorExtensions.x-extra-annotation}}}
|
||||
{{/vendorExtensions.x-extra-annotation}}
|
||||
{{#jackson}}
|
||||
@JsonProperty(value = "{{baseName}}"{{#isReadOnly}}, access = JsonProperty.Access.READ_ONLY{{/isReadOnly}}{{#isWriteOnly}}, access = JsonProperty.Access.WRITE_ONLY{{/isWriteOnly}})
|
||||
{{/jackson}}
|
||||
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}")
|
||||
{{#useBeanValidation}}{{#required}}{{^isReadOnly}}
|
||||
@NotNull
|
||||
{{/isReadOnly}}{{/required}}{{#isContainer}}{{! No @Valid on container; type has List<@Valid T> (HV000271) }}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}
|
||||
@Valid
|
||||
{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}}{{/useBeanValidation}}
|
||||
public {{>propertyType}} {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
|
||||
{{#vendorExtensions.x-setter-extra-annotation}}{{{vendorExtensions.x-setter-extra-annotation}}}
|
||||
{{/vendorExtensions.x-setter-extra-annotation}}public void {{setter}}({{>propertyType}} {{name}}) {
|
||||
this.{{name}} = {{name}};
|
||||
}
|
||||
|
||||
{{/vars}}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
{{classname}} {{classVarName}} = ({{classname}}) o;{{#hasVars}}
|
||||
return {{#parent}}super.equals(o) && {{/parent}}{{#vars}}Objects.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} &&
|
||||
{{/-last}}{{#-last}};{{/-last}}{{/vars}}{{/hasVars}}{{^hasVars}}{{#parent}}return super.equals(o);{{/parent}}{{^parent}}return true;{{/parent}}{{/hasVars}}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return {{^hasVars}}{{#parent}}super.hashCode(){{/parent}}{{^parent}}1{{/parent}}{{/hasVars}}{{#hasVars}}Objects.hash({{#vars}}{{#parent}}super.hashCode(), {{/parent}}{{name}}{{^-last}}, {{/-last}}{{/vars}}){{/hasVars}};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class {{classname}} {\n");
|
||||
{{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}}
|
||||
{{#vars}}sb.append(" {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n");
|
||||
{{/vars}}sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
{{! Type with @Valid on type argument for containers (HV000271 fix). }}{{#isContainer}}{{#isArray}}{{#items.isPrimitiveType}}{{{datatypeWithEnum}}}{{/items.isPrimitiveType}}{{^items.isPrimitiveType}}{{#items.isEnum}}{{{datatypeWithEnum}}}{{/items.isEnum}}{{^items.isEnum}}List<@Valid {{{items.datatypeWithEnum}}}>{{/items.isEnum}}{{/items.isPrimitiveType}}{{/isArray}}{{^isArray}}{{#isMap}}{{#items.isPrimitiveType}}{{{datatypeWithEnum}}}{{/items.isPrimitiveType}}{{^items.isPrimitiveType}}{{#items.isEnum}}{{{datatypeWithEnum}}}{{/items.isEnum}}{{^items.isEnum}}Map<String, @Valid {{{items.datatypeWithEnum}}}>{{/items.isEnum}}{{/items.isPrimitiveType}}{{/isMap}}{{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{/isMap}}{{/isArray}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}{{/isContainer}}
|
||||
@ -0,0 +1 @@
|
||||
{{#required}}{{^isReadOnly}}@NotNull {{/isReadOnly}}{{/required}}{{#isContainer}}{{! Do not add @Valid on container; use type-argument @Valid (HV000271) }}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{^isEnumOrRef}}@Valid {{/isEnumOrRef}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}}
|
||||
@ -0,0 +1,289 @@
|
||||
{{#useSwaggerAnnotations}}
|
||||
import io.swagger.annotations.*;
|
||||
{{/useSwaggerAnnotations}}
|
||||
{{#useSwaggerV3Annotations}}
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
{{/useSwaggerV3Annotations}}
|
||||
import java.util.Objects;
|
||||
{{#jackson}}
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
{{#additionalProperties}}
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
{{/additionalProperties}}
|
||||
{{/jackson}}
|
||||
{{#openApiNullable}}
|
||||
import org.openapitools.jackson.nullable.JsonNullable;
|
||||
{{/openApiNullable}}
|
||||
{{#withXml}}
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlElement;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlRootElement;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlAccessType;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlAccessorType;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlType;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlEnum;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue;
|
||||
{{/withXml}}
|
||||
|
||||
{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/**
|
||||
* {{.}}
|
||||
**/{{/description}}
|
||||
{{#useSwaggerAnnotations}}{{#description}}@ApiModel(description = "{{{.}}}"){{/description}}{{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}}
|
||||
@Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}}
|
||||
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useMicroProfileOpenAPIAnnotations}}
|
||||
{{#jackson}}
|
||||
@JsonTypeName("{{name}}")
|
||||
{{#additionalProperties}}
|
||||
@JsonFormat(shape=JsonFormat.Shape.OBJECT)
|
||||
{{/additionalProperties}}
|
||||
{{/jackson}}
|
||||
{{>generatedAnnotation}}{{>additionalModelTypeAnnotations}}{{>xmlPojoAnnotation}}
|
||||
{{#vendorExtensions.x-class-extra-annotation}}
|
||||
{{{vendorExtensions.x-class-extra-annotation}}}
|
||||
{{/vendorExtensions.x-class-extra-annotation}}
|
||||
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
{{^isContainer}}
|
||||
{{>enumClass}}{{! prevent indent}}
|
||||
{{/isContainer}}
|
||||
{{#isContainer}}
|
||||
{{#mostInnerItems}}
|
||||
{{>enumClass}}{{! prevent indent}}
|
||||
{{/mostInnerItems}}
|
||||
{{/isContainer}}
|
||||
{{/isEnum}}
|
||||
{{#vendorExtensions.x-field-extra-annotation}}
|
||||
{{{.}}}
|
||||
{{/vendorExtensions.x-field-extra-annotation}}
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{#isContainer}}
|
||||
private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>undefined();
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}};
|
||||
{{/isContainer}}
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
private {{#useBeanValidation}}{{>beanValidatedType}}{{/useBeanValidation}}{{^useBeanValidation}}{{{datatypeWithEnum}}}{{/useBeanValidation}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{/vars}}
|
||||
|
||||
{{#generateBuilders}}
|
||||
{{^additionalProperties}}
|
||||
protected {{classname}}({{classname}}Builder b) {
|
||||
{{#parent}}
|
||||
super(b);
|
||||
{{/parent}}
|
||||
{{#vars}}
|
||||
this.{{name}} = b.{{name}};
|
||||
{{/vars}}
|
||||
}
|
||||
|
||||
{{/additionalProperties}}
|
||||
{{/generateBuilders}}
|
||||
public {{classname}}() {
|
||||
}
|
||||
|
||||
{{#jackson}}
|
||||
{{#generateJsonCreator}}
|
||||
{{#hasRequired}}
|
||||
@JsonCreator
|
||||
public {{classname}}(
|
||||
{{#requiredVars}}
|
||||
@JsonProperty(required = {{required}}, value = "{{baseName}}") {{>beanValidatedType}} {{name}}{{^-last}},{{/-last}}
|
||||
{{/requiredVars}}
|
||||
) {
|
||||
{{#parent}}
|
||||
super(
|
||||
{{#parentRequiredVars}}
|
||||
{{name}}{{^-last}},{{/-last}}
|
||||
{{/parentRequiredVars}}
|
||||
);
|
||||
{{/parent}}
|
||||
{{#vars}}
|
||||
{{#required}}
|
||||
this.{{name}} = {{name}};
|
||||
{{/required}}
|
||||
{{/vars}}
|
||||
}
|
||||
|
||||
{{/hasRequired}}
|
||||
{{/generateJsonCreator}}
|
||||
{{/jackson}}
|
||||
{{#vars}}
|
||||
/**
|
||||
{{#description}}
|
||||
* {{.}}
|
||||
{{/description}}
|
||||
{{#minimum}}
|
||||
* minimum: {{.}}
|
||||
{{/minimum}}
|
||||
{{#maximum}}
|
||||
* maximum: {{.}}
|
||||
{{/maximum}}
|
||||
**/
|
||||
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = {{name}};
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
return this;
|
||||
}
|
||||
|
||||
{{#withXml}}
|
||||
@XmlElement(name="{{baseName}}"{{#required}}, required = {{required}}{{/required}})
|
||||
{{/withXml}}
|
||||
{{#vendorExtensions.x-extra-annotation}}{{{vendorExtensions.x-extra-annotation}}}{{/vendorExtensions.x-extra-annotation}}{{#useSwaggerAnnotations}}
|
||||
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}}
|
||||
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}}
|
||||
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useMicroProfileOpenAPIAnnotations}}
|
||||
{{#jackson}}@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}"){{/jackson}}
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
public JsonNullable<{{{datatypeWithEnum}}}> {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}public {{>beanValidatedType}} {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
|
||||
{{#jackson}}
|
||||
@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}")
|
||||
{{/jackson}}
|
||||
{{#vendorExtensions.x-setter-extra-annotation}}{{{vendorExtensions.x-setter-extra-annotation}}}
|
||||
{{/vendorExtensions.x-setter-extra-annotation}}public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = {{name}};
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
}
|
||||
|
||||
{{#isArray}}
|
||||
public {{classname}} add{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if (this.{{name}} == null) {
|
||||
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
|
||||
}
|
||||
|
||||
this.{{name}}.add({{name}}Item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public {{classname}} remove{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if ({{name}}Item != null && this.{{name}} != null) {
|
||||
this.{{name}}.remove({{name}}Item);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
{{/isArray}}
|
||||
{{#isMap}}
|
||||
public {{classname}} put{{nameInPascalCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if (this.{{name}} == null) {
|
||||
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
|
||||
}
|
||||
|
||||
this.{{name}}.put(key, {{name}}Item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public {{classname}} remove{{nameInPascalCase}}Item(String key) {
|
||||
if (this.{{name}} != null) {
|
||||
this.{{name}}.remove(key);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
{{/isMap}}
|
||||
{{/vars}}
|
||||
{{>additional_properties}}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}{{#hasVars}}
|
||||
{{classname}} {{classVarName}} = ({{classname}}) o;
|
||||
return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} &&
|
||||
{{/-last}}{{/vars}}{{#parent}} &&
|
||||
super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}}
|
||||
return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};{{/hasVars}}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class {{classname}} {\n");
|
||||
{{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}}
|
||||
{{#vars}}sb.append(" {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n");
|
||||
{{/vars}}sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
|
||||
{{#generateBuilders}}{{^additionalProperties}}
|
||||
public static {{classname}}Builder builder() {
|
||||
return new {{classname}}BuilderImpl();
|
||||
}
|
||||
|
||||
private static final class {{classname}}BuilderImpl extends {{classname}}Builder<{{classname}}, {{classname}}BuilderImpl> {
|
||||
|
||||
@Override
|
||||
protected {{classname}}BuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public {{classname}} build() {
|
||||
return new {{classname}}(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class {{classname}}Builder > {{#parent}}extends {{{.}}}Builder {{/parent}} {
|
||||
{{#vars}}
|
||||
private {{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
|
||||
{{/vars}}
|
||||
{{^parent}}
|
||||
protected abstract B self();
|
||||
|
||||
public abstract C build();
|
||||
{{/parent}}
|
||||
|
||||
{{#vars}}
|
||||
public B {{name}}({{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}) {
|
||||
this.{{name}} = {{name}};
|
||||
return self();
|
||||
}
|
||||
{{/vars}}
|
||||
}{{/additionalProperties}}{{/generateBuilders}}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
{{#additionalEnumTypeAnnotations}}{{{.}}}
|
||||
{{/additionalEnumTypeAnnotations}}
|
||||
@ -0,0 +1,2 @@
|
||||
{{#additionalModelTypeAnnotations}}{{{.}}}
|
||||
{{/additionalModelTypeAnnotations}}
|
||||
@ -0,0 +1,32 @@
|
||||
{{#additionalProperties}}
|
||||
/**
|
||||
* Set the additional (undeclared) property with the specified name and value.
|
||||
* Creates the property if it does not already exist, otherwise replaces it.
|
||||
* @param key the name of the property
|
||||
* @param value the value of the property
|
||||
* @return self reference
|
||||
*/
|
||||
@JsonAnySetter
|
||||
public {{classname}} putAdditionalProperty(String key, {{{datatypeWithEnum}}} value) {
|
||||
this.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the additional (undeclared) properties.
|
||||
* @return the additional (undeclared) properties
|
||||
*/
|
||||
@JsonAnyGetter
|
||||
public Map getAdditionalProperties() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the additional (undeclared) property with the specified name.
|
||||
* @param key the name of the property
|
||||
* @return the additional (undeclared) property with the specified name
|
||||
*/
|
||||
public {{{datatypeWithEnum}}} getAdditionalProperty(String key) {
|
||||
return this.get(key);
|
||||
}
|
||||
{{/additionalProperties}}
|
||||
@ -0,0 +1 @@
|
||||
{{#isArray}}{{baseType}}<{{#items}}{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}{{>beanValidatedType}}{{/items}}>{{/isArray}}{{^isArray}}{{{datatypeWithEnum}}}{{/isArray}}
|
||||
@ -0,0 +1 @@
|
||||
{{#required}}{{^isReadOnly}}@NotNull {{/isReadOnly}}{{/required}}{{#isContainer}}{{! No @Valid on container (HV000271) }}{{/isContainer}}{{^isContainer}}{{^isPrimitiveType}}{{^isDate}}{{^isDateTime}}{{^isString}}{{^isFile}}{{^isEnumOrRef}}@Valid {{/isEnumOrRef}}{{/isFile}}{{/isString}}{{/isDateTime}}{{/isDate}}{{/isPrimitiveType}}{{/isContainer}}{{>beanValidationCore}}
|
||||
@ -0,0 +1,20 @@
|
||||
{{#pattern}} @Pattern(regexp="{{{.}}}"){{/pattern}}{{!
|
||||
minLength && maxLength set
|
||||
}}{{#minLength}}{{#maxLength}} @Size(min={{minLength}},max={{maxLength}}){{/maxLength}}{{/minLength}}{{!
|
||||
minLength set, maxLength not
|
||||
}}{{#minLength}}{{^maxLength}} @Size(min={{minLength}}){{/maxLength}}{{/minLength}}{{!
|
||||
minLength not set, maxLength set
|
||||
}}{{^minLength}}{{#maxLength}} @Size(max={{.}}){{/maxLength}}{{/minLength}}{{!
|
||||
@Size: minItems && maxItems set
|
||||
}}{{#minItems}}{{#maxItems}} @Size(min={{minItems}},max={{maxItems}}){{/maxItems}}{{/minItems}}{{!
|
||||
@Size: minItems set, maxItems not
|
||||
}}{{#minItems}}{{^maxItems}} @Size(min={{minItems}}){{/maxItems}}{{/minItems}}{{!
|
||||
@Size: minItems not set && maxItems set
|
||||
}}{{^minItems}}{{#maxItems}} @Size(max={{.}}){{/maxItems}}{{/minItems}}{{!
|
||||
check for integer or long / all others=decimal type with @Decimal*
|
||||
isInteger set
|
||||
}}{{#isInteger}}{{#minimum}} @Min({{.}}){{/minimum}}{{#maximum}} @Max({{.}}){{/maximum}}{{/isInteger}}{{!
|
||||
isLong set
|
||||
}}{{#isLong}}{{#minimum}} @Min({{.}}L){{/minimum}}{{#maximum}} @Max({{.}}L){{/maximum}}{{/isLong}}{{!
|
||||
Not Integer, not Long => we have a decimal value!
|
||||
}}{{^isInteger}}{{^isLong}}{{#minimum}} @DecimalMin({{#exclusiveMinimum}}value={{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}},inclusive=false{{/exclusiveMinimum}}){{/minimum}}{{#maximum}} @DecimalMax({{#exclusiveMaximum}}value={{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}},inclusive=false{{/exclusiveMaximum}}){{/maximum}}{{/isLong}}{{/isInteger}}
|
||||
56
src/main/resources/openapi-templates/enumClass.mustache
Normal file
56
src/main/resources/openapi-templates/enumClass.mustache
Normal file
@ -0,0 +1,56 @@
|
||||
{{#withXml}}
|
||||
@XmlType(name="{{datatypeWithEnum}}")
|
||||
@XmlEnum({{dataType}}.class)
|
||||
{{/withXml}}
|
||||
{{>additionalEnumTypeAnnotations}}public enum {{datatypeWithEnum}} {
|
||||
|
||||
{{#allowableValues}}
|
||||
{{#enumVars}}{{#withXml}}@XmlEnumValue({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}){{/withXml}}{{name}}({{dataType}}.valueOf({{{value}}})){{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}
|
||||
{{/allowableValues}}
|
||||
|
||||
|
||||
private {{dataType}} value;
|
||||
|
||||
{{datatypeWithEnum}} ({{dataType}} v) {
|
||||
value = v;
|
||||
}
|
||||
|
||||
public {{dataType}} value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
{{#jackson}}
|
||||
@JsonValue
|
||||
{{/jackson}}
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a String into {{dataType}}, as specified in the
|
||||
* See JAX RS 2.0 Specification, section 3.2, p. 12
|
||||
*/
|
||||
public static {{datatypeWithEnum}} fromString(String s) {
|
||||
for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
|
||||
// using Objects.toString() to be safe if value type non-object type
|
||||
// because types like 'int' etc. will be auto-boxed
|
||||
if (java.util.Objects.toString(b.value).equals(s)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected string value '" + s + "'");{{/isNullable}}
|
||||
}
|
||||
|
||||
{{#jackson}}
|
||||
@JsonCreator
|
||||
public static {{datatypeWithEnum}} fromValue({{dataType}} value) {
|
||||
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
|
||||
if (b.value.{{^isString}}equals{{/isString}}{{#isString}}{{#useEnumCaseInsensitive}}equalsIgnoreCase{{/useEnumCaseInsensitive}}{{^useEnumCaseInsensitive}}equals{{/useEnumCaseInsensitive}}{{/isString}}(value)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}{{#enumUnknownDefaultCase}}{{#allowableValues}}{{#enumVars}}{{#-last}}return {{{name}}};{{/-last}}{{/enumVars}}{{/allowableValues}}{{/enumUnknownDefaultCase}}{{^enumUnknownDefaultCase}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/enumUnknownDefaultCase}}{{/isNullable}}
|
||||
}
|
||||
{{/jackson}}
|
||||
}
|
||||
64
src/main/resources/openapi-templates/enumOuterClass.mustache
Normal file
64
src/main/resources/openapi-templates/enumOuterClass.mustache
Normal file
@ -0,0 +1,64 @@
|
||||
{{#jackson}}
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
{{/jackson}}
|
||||
|
||||
/**
|
||||
* {{description}}{{^description}}Gets or Sets {{{name}}}{{/description}}
|
||||
*/
|
||||
{{>generatedAnnotation}}
|
||||
|
||||
{{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} {
|
||||
{{#gson}}
|
||||
{{#allowableValues}}{{#enumVars}}
|
||||
@SerializedName({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}})
|
||||
{{{name}}}({{{value}}}){{^-last}},
|
||||
{{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}}
|
||||
{{/gson}}
|
||||
{{^gson}}
|
||||
{{#allowableValues}}{{#enumVars}}
|
||||
{{{name}}}({{{value}}}){{^-last}},
|
||||
{{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}}
|
||||
{{/gson}}
|
||||
|
||||
private {{{dataType}}} value;
|
||||
|
||||
{{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a String into {{dataType}}, as specified in the
|
||||
* See JAX RS 2.0 Specification, section 3.2, p. 12
|
||||
*/
|
||||
public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromString(String s) {
|
||||
for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
|
||||
// using Objects.toString() to be safe if value type non-object type
|
||||
// because types like 'int' etc. will be auto-boxed
|
||||
if (java.util.Objects.toString(b.value).equals(s)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}throw new IllegalArgumentException("Unexpected string value '" + s + "'");{{/isNullable}}
|
||||
}
|
||||
|
||||
@Override
|
||||
{{#jackson}}
|
||||
@JsonValue
|
||||
{{/jackson}}
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
{{#jackson}}
|
||||
@JsonCreator
|
||||
public static {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} value) {
|
||||
for ({{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) {
|
||||
if (b.value.{{^isString}}equals{{/isString}}{{#isString}}{{#useEnumCaseInsensitive}}equalsIgnoreCase{{/useEnumCaseInsensitive}}{{^useEnumCaseInsensitive}}equals{{/useEnumCaseInsensitive}}{{/isString}}(value)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
{{#isNullable}}return null;{{/isNullable}}{{^isNullable}}{{#enumUnknownDefaultCase}}{{#allowableValues}}{{#enumVars}}{{#-last}}return {{{name}}};{{/-last}}{{/enumVars}}{{/allowableValues}}{{/enumUnknownDefaultCase}}{{^enumUnknownDefaultCase}}throw new IllegalArgumentException("Unexpected value '" + value + "'");{{/enumUnknownDefaultCase}}{{/isNullable}}
|
||||
}
|
||||
{{/jackson}}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
@{{javaxPackage}}.annotation.Generated(value = "{{generatorClass}}"{{^hideGenerationTimestamp}}, date = "{{generatedDate}}"{{/hideGenerationTimestamp}}, comments = "Generator version: {{generatorVersion}}")
|
||||
21
src/main/resources/openapi-templates/model.mustache
Normal file
21
src/main/resources/openapi-templates/model.mustache
Normal file
@ -0,0 +1,21 @@
|
||||
package {{package}};
|
||||
|
||||
{{#imports}}import {{import}};
|
||||
{{/imports}}
|
||||
{{#serializableModel}}
|
||||
import java.io.Serializable;
|
||||
{{/serializableModel}}
|
||||
{{#useBeanValidation}}
|
||||
import {{javaxPackage}}.validation.constraints.*;
|
||||
import {{javaxPackage}}.validation.Valid;
|
||||
{{/useBeanValidation}}
|
||||
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
{{#isEnum}}
|
||||
{{>enumOuterClass}}
|
||||
|
||||
{{/isEnum}}
|
||||
{{^isEnum}}{{>pojo}}{{/isEnum}}
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
289
src/main/resources/openapi-templates/pojo.mustache
Normal file
289
src/main/resources/openapi-templates/pojo.mustache
Normal file
@ -0,0 +1,289 @@
|
||||
{{#useSwaggerAnnotations}}
|
||||
import io.swagger.annotations.*;
|
||||
{{/useSwaggerAnnotations}}
|
||||
{{#useSwaggerV3Annotations}}
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
{{/useSwaggerV3Annotations}}
|
||||
import java.util.Objects;
|
||||
{{#jackson}}
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
{{#additionalProperties}}
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
{{/additionalProperties}}
|
||||
{{/jackson}}
|
||||
{{#openApiNullable}}
|
||||
import org.openapitools.jackson.nullable.JsonNullable;
|
||||
{{/openApiNullable}}
|
||||
{{#withXml}}
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlElement;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlRootElement;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlAccessType;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlAccessorType;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlType;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlEnum;
|
||||
import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue;
|
||||
{{/withXml}}
|
||||
|
||||
{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/**
|
||||
* {{.}}
|
||||
**/{{/description}}
|
||||
{{#useSwaggerAnnotations}}{{#description}}@ApiModel(description = "{{{.}}}"){{/description}}{{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}}
|
||||
@Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}}
|
||||
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useMicroProfileOpenAPIAnnotations}}
|
||||
{{#jackson}}
|
||||
@JsonTypeName("{{name}}")
|
||||
{{#additionalProperties}}
|
||||
@JsonFormat(shape=JsonFormat.Shape.OBJECT)
|
||||
{{/additionalProperties}}
|
||||
{{/jackson}}
|
||||
{{>generatedAnnotation}}{{>additionalModelTypeAnnotations}}{{>xmlPojoAnnotation}}
|
||||
{{#vendorExtensions.x-class-extra-annotation}}
|
||||
{{{vendorExtensions.x-class-extra-annotation}}}
|
||||
{{/vendorExtensions.x-class-extra-annotation}}
|
||||
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
{{^isContainer}}
|
||||
{{>enumClass}}{{! prevent indent}}
|
||||
{{/isContainer}}
|
||||
{{#isContainer}}
|
||||
{{#mostInnerItems}}
|
||||
{{>enumClass}}{{! prevent indent}}
|
||||
{{/mostInnerItems}}
|
||||
{{/isContainer}}
|
||||
{{/isEnum}}
|
||||
{{#vendorExtensions.x-field-extra-annotation}}
|
||||
{{{.}}}
|
||||
{{/vendorExtensions.x-field-extra-annotation}}
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{#isContainer}}
|
||||
private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>undefined();
|
||||
{{/isContainer}}
|
||||
{{^isContainer}}
|
||||
private JsonNullable<{{{datatypeWithEnum}}}> {{name}} = JsonNullable.<{{{datatypeWithEnum}}}>{{#defaultValue}}of({{{.}}}){{/defaultValue}}{{^defaultValue}}undefined(){{/defaultValue}};
|
||||
{{/isContainer}}
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
private {{#useBeanValidation}}{{>beanValidatedType}}{{/useBeanValidation}}{{^useBeanValidation}}{{{datatypeWithEnum}}}{{/useBeanValidation}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{/vars}}
|
||||
|
||||
{{#generateBuilders}}
|
||||
{{^additionalProperties}}
|
||||
protected {{classname}}({{classname}}Builder b) {
|
||||
{{#parent}}
|
||||
super(b);
|
||||
{{/parent}}
|
||||
{{#vars}}
|
||||
this.{{name}} = b.{{name}};
|
||||
{{/vars}}
|
||||
}
|
||||
|
||||
{{/additionalProperties}}
|
||||
{{/generateBuilders}}
|
||||
public {{classname}}() {
|
||||
}
|
||||
|
||||
{{#jackson}}
|
||||
{{#generateJsonCreator}}
|
||||
{{#hasRequired}}
|
||||
@JsonCreator
|
||||
public {{classname}}(
|
||||
{{#requiredVars}}
|
||||
@JsonProperty(required = {{required}}, value = "{{baseName}}") {{>beanValidatedType}} {{name}}{{^-last}},{{/-last}}
|
||||
{{/requiredVars}}
|
||||
) {
|
||||
{{#parent}}
|
||||
super(
|
||||
{{#parentRequiredVars}}
|
||||
{{name}}{{^-last}},{{/-last}}
|
||||
{{/parentRequiredVars}}
|
||||
);
|
||||
{{/parent}}
|
||||
{{#vars}}
|
||||
{{#required}}
|
||||
this.{{name}} = {{name}};
|
||||
{{/required}}
|
||||
{{/vars}}
|
||||
}
|
||||
|
||||
{{/hasRequired}}
|
||||
{{/generateJsonCreator}}
|
||||
{{/jackson}}
|
||||
{{#vars}}
|
||||
/**
|
||||
{{#description}}
|
||||
* {{.}}
|
||||
{{/description}}
|
||||
{{#minimum}}
|
||||
* minimum: {{.}}
|
||||
{{/minimum}}
|
||||
{{#maximum}}
|
||||
* maximum: {{.}}
|
||||
{{/maximum}}
|
||||
**/
|
||||
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = {{name}};
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
return this;
|
||||
}
|
||||
|
||||
{{#withXml}}
|
||||
@XmlElement(name="{{baseName}}"{{#required}}, required = {{required}}{{/required}})
|
||||
{{/withXml}}
|
||||
{{#vendorExtensions.x-extra-annotation}}{{{vendorExtensions.x-extra-annotation}}}{{/vendorExtensions.x-extra-annotation}}{{#useSwaggerAnnotations}}
|
||||
@ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}}
|
||||
@Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}}
|
||||
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useMicroProfileOpenAPIAnnotations}}
|
||||
{{#jackson}}@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}"){{/jackson}}
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
public JsonNullable<{{{datatypeWithEnum}}}> {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}public {{>beanValidatedType}} {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
|
||||
{{#jackson}}
|
||||
@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}")
|
||||
{{/jackson}}
|
||||
{{#vendorExtensions.x-setter-extra-annotation}}{{{vendorExtensions.x-setter-extra-annotation}}}
|
||||
{{/vendorExtensions.x-setter-extra-annotation}}public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
|
||||
{{#vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}});
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
{{^vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
this.{{name}} = {{name}};
|
||||
{{/vendorExtensions.x-is-jackson-optional-nullable}}
|
||||
}
|
||||
|
||||
{{#isArray}}
|
||||
public {{classname}} add{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if (this.{{name}} == null) {
|
||||
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
|
||||
}
|
||||
|
||||
this.{{name}}.add({{name}}Item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public {{classname}} remove{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if ({{name}}Item != null && this.{{name}} != null) {
|
||||
this.{{name}}.remove({{name}}Item);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
{{/isArray}}
|
||||
{{#isMap}}
|
||||
public {{classname}} put{{nameInPascalCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
|
||||
if (this.{{name}} == null) {
|
||||
this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
|
||||
}
|
||||
|
||||
this.{{name}}.put(key, {{name}}Item);
|
||||
return this;
|
||||
}
|
||||
|
||||
public {{classname}} remove{{nameInPascalCase}}Item(String key) {
|
||||
if (this.{{name}} != null) {
|
||||
this.{{name}}.remove(key);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
{{/isMap}}
|
||||
{{/vars}}
|
||||
{{>additional_properties}}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}{{#hasVars}}
|
||||
{{classname}} {{classVarName}} = ({{classname}}) o;
|
||||
return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} &&
|
||||
{{/-last}}{{/vars}}{{#parent}} &&
|
||||
super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}}
|
||||
return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};{{/hasVars}}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class {{classname}} {\n");
|
||||
{{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}}
|
||||
{{#vars}}sb.append(" {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n");
|
||||
{{/vars}}sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
|
||||
{{#generateBuilders}}{{^additionalProperties}}
|
||||
public static {{classname}}Builder builder() {
|
||||
return new {{classname}}BuilderImpl();
|
||||
}
|
||||
|
||||
private static final class {{classname}}BuilderImpl extends {{classname}}Builder<{{classname}}, {{classname}}BuilderImpl> {
|
||||
|
||||
@Override
|
||||
protected {{classname}}BuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public {{classname}} build() {
|
||||
return new {{classname}}(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class {{classname}}Builder > {{#parent}}extends {{{.}}}Builder {{/parent}} {
|
||||
{{#vars}}
|
||||
private {{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
|
||||
{{/vars}}
|
||||
{{^parent}}
|
||||
protected abstract B self();
|
||||
|
||||
public abstract C build();
|
||||
{{/parent}}
|
||||
|
||||
{{#vars}}
|
||||
public B {{name}}({{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}) {
|
||||
this.{{name}} = {{name}};
|
||||
return self();
|
||||
}
|
||||
{{/vars}}
|
||||
}{{/additionalProperties}}{{/generateBuilders}}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
{{#jackson}}
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
|
||||
@JsonSubTypes({
|
||||
{{#discriminator.mappedModels}}
|
||||
@JsonSubTypes.Type(value = {{modelName}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{mappingName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"),
|
||||
{{/discriminator.mappedModels}}
|
||||
})
|
||||
{{/jackson}}
|
||||
@ -0,0 +1,8 @@
|
||||
{{#withXml}}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
{{#hasVars}} @XmlType(name = "{{classname}}", propOrder =
|
||||
{ {{#vars}}"{{name}}"{{^-last}}, {{/-last}}{{/vars}}
|
||||
}){{/hasVars}}
|
||||
{{^hasVars}}@XmlType(name = "{{classname}}"){{/hasVars}}
|
||||
{{^parent}}@XmlRootElement(name="{{classname}}"){{/parent}}
|
||||
{{/withXml}}
|
||||
@ -36,11 +36,13 @@ import type {
|
||||
CreateSessionRequest,
|
||||
ModelInfo,
|
||||
ScenarioSetup,
|
||||
ScenarioSummary,
|
||||
} from '../api/generated/index'
|
||||
import {
|
||||
Configuration,
|
||||
CreateSessionRequestSafetyLevelEnum,
|
||||
ModelsApi,
|
||||
ScenariosApi,
|
||||
SessionsApi,
|
||||
} from '../api/generated/index'
|
||||
|
||||
@ -49,6 +51,7 @@ const API_BASE = '/api/v1'
|
||||
|
||||
const modelsApi = new ModelsApi(new Configuration({basePath: API_BASE}))
|
||||
const sessionsApi = new SessionsApi(new Configuration({basePath: API_BASE}))
|
||||
const scenariosApi = new ScenariosApi(new Configuration({basePath: API_BASE}))
|
||||
|
||||
/**
|
||||
* Landing page where the user selects an Ollama model and optional settings
|
||||
@ -64,6 +67,9 @@ export default function StartPage() {
|
||||
const [starting, setStarting] = useState<boolean>(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
/** Saved scenarios from API; selectedScenarioId is '' for custom or a UUID. */
|
||||
const [scenarios, setScenarios] = useState<ScenarioSummary[]>([])
|
||||
const [selectedScenarioId, setSelectedScenarioId] = useState<string>('')
|
||||
/** Optional scenario (collapsible). */
|
||||
const [scenarioExpanded, setScenarioExpanded] = useState<boolean>(false)
|
||||
const [setting, setSetting] = useState<string>('')
|
||||
@ -77,14 +83,18 @@ export default function StartPage() {
|
||||
draft: CharacterDefinition
|
||||
} | null>(null)
|
||||
|
||||
/** Load available models on mount. */
|
||||
/** Load available models and saved scenarios on mount. */
|
||||
useEffect(() => {
|
||||
modelsApi.listModels()
|
||||
.then((resp) => {
|
||||
setModels(resp.models ?? [])
|
||||
if (resp.models && resp.models.length > 0) {
|
||||
setSelectedModel(resp.models[0].name)
|
||||
Promise.all([
|
||||
modelsApi.listModels(),
|
||||
scenariosApi.listScenarios().catch(() => ({scenarios: []})),
|
||||
])
|
||||
.then(([modelsResp, scenariosResp]) => {
|
||||
setModels(modelsResp.models ?? [])
|
||||
if (modelsResp.models && modelsResp.models.length > 0) {
|
||||
setSelectedModel(modelsResp.models[0].name)
|
||||
}
|
||||
setScenarios(scenariosResp.scenarios ?? [])
|
||||
})
|
||||
.catch(() => setError('Could not load models. Is the Quarkus server running?'))
|
||||
.finally(() => setLoading(false))
|
||||
@ -94,6 +104,22 @@ export default function StartPage() {
|
||||
setSelectedModel(event.target.value)
|
||||
}
|
||||
|
||||
/** When user selects a saved scenario, load its full setup and prefill the form. */
|
||||
const handleScenarioSelect = async (event: SelectChangeEvent<string>) => {
|
||||
const id = event.target.value
|
||||
setSelectedScenarioId(id)
|
||||
if (!id) return
|
||||
try {
|
||||
const setup = await scenariosApi.getScenario({scenarioId: id})
|
||||
setSetting(setup.setting ?? '')
|
||||
setInitialConflict(setup.initialConflict ?? '')
|
||||
setUserCharacter(setup.userCharacter ?? null)
|
||||
setAiCharacters(setup.aiCharacters ?? [])
|
||||
} catch {
|
||||
setError('Could not load scenario.')
|
||||
}
|
||||
}
|
||||
|
||||
/** Build scenario from form state if any field is filled. */
|
||||
const buildScenario = (): ScenarioSetup | undefined => {
|
||||
const hasSetting = setting.trim() !== ''
|
||||
@ -166,7 +192,8 @@ export default function StartPage() {
|
||||
model: selectedModel,
|
||||
language,
|
||||
safetyLevel: CreateSessionRequestSafetyLevelEnum.standard,
|
||||
scenario: buildScenario(),
|
||||
scenarioId: selectedScenarioId || undefined,
|
||||
scenario: selectedScenarioId ? undefined : buildScenario(),
|
||||
}
|
||||
const session = await sessionsApi.createSession({createSessionRequest: request})
|
||||
navigate(`/session/${session.sessionId}`)
|
||||
@ -229,6 +256,25 @@ export default function StartPage() {
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<FormControl fullWidth disabled={starting} sx={{mb: 1}}>
|
||||
<InputLabel id="scenario-label">Saved scenario</InputLabel>
|
||||
<Select
|
||||
labelId="scenario-label"
|
||||
value={selectedScenarioId}
|
||||
label="Saved scenario"
|
||||
onChange={handleScenarioSelect}
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>Custom (none)</em>
|
||||
</MenuItem>
|
||||
{scenarios.map((s) => (
|
||||
<MenuItem key={s.id} value={s.id}>
|
||||
{s.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<Accordion
|
||||
expanded={scenarioExpanded}
|
||||
onChange={() => setScenarioExpanded((b) => !b)}
|
||||
|
||||
@ -21,6 +21,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
@ -39,18 +40,21 @@ class InMemorySessionServiceTest {
|
||||
@Mock
|
||||
private OllamaClient ollamaClient;
|
||||
|
||||
@Mock
|
||||
private ScenarioService scenarioService;
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private InMemorySessionService sessionService;
|
||||
|
||||
/**
|
||||
* Creates a fresh service instance with mocked Ollama client before each test.
|
||||
* Creates a fresh service instance with mocked Ollama client and scenario service before each test.
|
||||
* By default, Ollama is stubbed to return a short narrative and an empty
|
||||
* state update so that createSession (with scenario) and submitTurn complete.
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
sessionService = new InMemorySessionService(ollamaClient, objectMapper);
|
||||
sessionService = new InMemorySessionService(ollamaClient, objectMapper, scenarioService);
|
||||
StateUpdateResponse emptyUpdate = StateUpdateResponse.builder()
|
||||
.responses(null)
|
||||
.updatedSituation(null)
|
||||
@ -238,6 +242,42 @@ class InMemorySessionServiceTest {
|
||||
assertEquals("Old Sage", aiState.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that creating a session with scenarioId uses the scenario loaded from the database.
|
||||
*/
|
||||
@Test
|
||||
void createSessionWithScenarioIdUsesScenarioFromDatabase() {
|
||||
UUID scenarioId = UUID.fromString("22222222-2222-2222-2222-222222222201");
|
||||
CharacterDefinition userChar = new CharacterDefinition("db_user", "DB User", "protagonist");
|
||||
CharacterDefinition aiChar = new CharacterDefinition("db_ai", "DB NPC", "antagonist");
|
||||
ScenarioSetup loadedScenario = new ScenarioSetup();
|
||||
loadedScenario.setSetting("Database setting");
|
||||
loadedScenario.setInitialConflict("Database conflict");
|
||||
loadedScenario.setUserCharacter(userChar);
|
||||
loadedScenario.setAiCharacters(List.of(aiChar));
|
||||
when(scenarioService.getScenarioAsSetup(scenarioId)).thenReturn(Optional.of(loadedScenario));
|
||||
|
||||
CreateSessionRequest request = new CreateSessionRequest("llama3:latest");
|
||||
request.setScenarioId(scenarioId);
|
||||
request.setScenario(null);
|
||||
|
||||
SessionResponse response = sessionService.createSession(request);
|
||||
|
||||
assertNotNull(response.getSituation());
|
||||
assertEquals("Database setting", response.getSituation().getSetting());
|
||||
assertNotNull(response.getCharacters());
|
||||
assertEquals(2, response.getCharacters().size());
|
||||
CharacterState userState = response.getCharacters().stream()
|
||||
.filter(c -> Boolean.TRUE.equals(c.getIsUserCharacter()))
|
||||
.findFirst().orElseThrow();
|
||||
assertEquals("db_user", userState.getId());
|
||||
assertEquals("DB User", userState.getName());
|
||||
CharacterState aiState = response.getCharacters().stream()
|
||||
.filter(c -> Boolean.FALSE.equals(c.getIsUserCharacter()))
|
||||
.findFirst().orElseThrow();
|
||||
assertEquals("db_ai", aiState.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that updateSession updates situation and characters when provided.
|
||||
*/
|
||||
|
||||
@ -0,0 +1,127 @@
|
||||
package de.neitzel.roleplay.business;
|
||||
|
||||
import de.neitzel.roleplay.data.CharacterEntity;
|
||||
import de.neitzel.roleplay.data.ScenarioCharacterEntity;
|
||||
import de.neitzel.roleplay.data.ScenarioEntity;
|
||||
import de.neitzel.roleplay.data.ScenarioRepository;
|
||||
import de.neitzel.roleplay.fascade.model.ScenarioSetup;
|
||||
import de.neitzel.roleplay.fascade.model.ScenarioSummary;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ScenarioService}.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ScenarioServiceTest {
|
||||
|
||||
@Mock
|
||||
private ScenarioRepository scenarioRepository;
|
||||
|
||||
private ScenarioService scenarioService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
scenarioService = new ScenarioService(scenarioRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
void listScenariosReturnsMappedSummaries() {
|
||||
ScenarioEntity entity = new ScenarioEntity();
|
||||
entity.setId(UUID.fromString("22222222-2222-2222-2222-222222222201"));
|
||||
entity.setName("Harbour mystery");
|
||||
entity.setSetting("A fog-covered harbour");
|
||||
entity.setInitialConflict("Strange noises");
|
||||
when(scenarioRepository.listAll()).thenReturn(List.of(entity));
|
||||
|
||||
List<ScenarioSummary> result = scenarioService.listScenarios();
|
||||
|
||||
assertEquals(1, result.size());
|
||||
ScenarioSummary summary = result.get(0);
|
||||
assertEquals(UUID.fromString("22222222-2222-2222-2222-222222222201"), summary.getId());
|
||||
assertEquals("Harbour mystery", summary.getName());
|
||||
assertEquals("A fog-covered harbour", summary.getSetting());
|
||||
assertEquals("Strange noises", summary.getInitialConflict());
|
||||
}
|
||||
|
||||
@Test
|
||||
void listScenariosReturnsEmptyWhenNoneStored() {
|
||||
when(scenarioRepository.listAll()).thenReturn(List.of());
|
||||
|
||||
List<ScenarioSummary> result = scenarioService.listScenarios();
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getScenarioAsSetupReturnsEmptyWhenNotFound() {
|
||||
UUID id = UUID.randomUUID();
|
||||
when(scenarioRepository.findByIdWithCharacters(id)).thenReturn(null);
|
||||
|
||||
Optional<ScenarioSetup> result = scenarioService.getScenarioAsSetup(id);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getScenarioAsSetupReturnsSetupWithUserAndAiCharacters() {
|
||||
UUID scenarioId = UUID.fromString("22222222-2222-2222-2222-222222222201");
|
||||
UUID userCharId = UUID.fromString("11111111-1111-1111-1111-111111111101");
|
||||
UUID aiCharId = UUID.fromString("11111111-1111-1111-1111-111111111102");
|
||||
|
||||
CharacterEntity userCharEntity = new CharacterEntity();
|
||||
userCharEntity.setId(userCharId);
|
||||
userCharEntity.setName("The Detective");
|
||||
userCharEntity.setRole("detective");
|
||||
|
||||
CharacterEntity aiCharEntity = new CharacterEntity();
|
||||
aiCharEntity.setId(aiCharId);
|
||||
aiCharEntity.setName("Captain Morgan");
|
||||
aiCharEntity.setRole("captain");
|
||||
|
||||
ScenarioCharacterEntity userLink = new ScenarioCharacterEntity();
|
||||
userLink.setUserCharacter(true);
|
||||
userLink.setPosition(0);
|
||||
userLink.setCharacter(userCharEntity);
|
||||
|
||||
ScenarioCharacterEntity aiLink = new ScenarioCharacterEntity();
|
||||
aiLink.setUserCharacter(false);
|
||||
aiLink.setPosition(1);
|
||||
aiLink.setCharacter(aiCharEntity);
|
||||
|
||||
ScenarioEntity scenarioEntity = new ScenarioEntity();
|
||||
scenarioEntity.setId(scenarioId);
|
||||
scenarioEntity.setName("Harbour mystery");
|
||||
scenarioEntity.setSetting("A fog-covered harbour at dawn");
|
||||
scenarioEntity.setInitialConflict("Strange noises from the cargo hold");
|
||||
scenarioEntity.setScenarioCharacters(List.of(userLink, aiLink));
|
||||
|
||||
when(scenarioRepository.findByIdWithCharacters(scenarioId)).thenReturn(scenarioEntity);
|
||||
|
||||
Optional<ScenarioSetup> result = scenarioService.getScenarioAsSetup(scenarioId);
|
||||
|
||||
assertTrue(result.isPresent());
|
||||
ScenarioSetup setup = result.get();
|
||||
assertEquals("A fog-covered harbour at dawn", setup.getSetting());
|
||||
assertEquals("Strange noises from the cargo hold", setup.getInitialConflict());
|
||||
assertNotNull(setup.getUserCharacter());
|
||||
assertEquals("The Detective", setup.getUserCharacter().getName());
|
||||
assertEquals("detective", setup.getUserCharacter().getRole());
|
||||
assertNotNull(setup.getAiCharacters());
|
||||
assertEquals(1, setup.getAiCharacters().size());
|
||||
assertEquals("Captain Morgan", setup.getAiCharacters().get(0).getName());
|
||||
assertEquals("captain", setup.getAiCharacters().get(0).getRole());
|
||||
}
|
||||
}
|
||||
216
tree.txt
Normal file
216
tree.txt
Normal file
@ -0,0 +1,216 @@
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ------------------------< de.neitzel:roleplay >-------------------------
|
||||
[INFO] Building roleplay 0.1.0-SNAPSHOT
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- dependency:3.7.0:tree (default-cli) @ roleplay ---
|
||||
[INFO] de.neitzel:roleplay:jar:0.1.0-SNAPSHOT
|
||||
[INFO] +- io.quarkus:quarkus-arc:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus.arc:arc:jar:3.31.1:compile
|
||||
[INFO] | | +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:4.1.0:compile
|
||||
[INFO] | | | +- jakarta.enterprise:jakarta.enterprise.lang-model:jar:4.1.0:compile
|
||||
[INFO] | | | \- jakarta.interceptor:jakarta.interceptor-api:jar:2.2.0:compile
|
||||
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:3.0.0:compile
|
||||
[INFO] | | +- jakarta.transaction:jakarta.transaction-api:jar:2.0.1:compile
|
||||
[INFO] | | +- io.smallrye.reactive:mutiny:jar:3.1.0:compile
|
||||
[INFO] | | | +- io.smallrye.common:smallrye-common-annotation:jar:2.15.0:compile
|
||||
[INFO] | | | \- org.jctools:jctools-core:jar:4.0.5:compile
|
||||
[INFO] | | \- org.jboss.logging:jboss-logging:jar:3.6.2.Final:compile
|
||||
[INFO] | +- io.quarkus:quarkus-core:jar:3.31.1:compile
|
||||
[INFO] | | +- jakarta.inject:jakarta.inject-api:jar:2.0.1:compile
|
||||
[INFO] | | +- io.smallrye.common:smallrye-common-os:jar:2.15.0:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-ide-launcher:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-development-mode-spi:jar:3.31.1:compile
|
||||
[INFO] | | +- io.smallrye.config:smallrye-config:jar:3.15.1:compile
|
||||
[INFO] | | | \- io.smallrye.config:smallrye-config-core:jar:3.15.1:compile
|
||||
[INFO] | | +- org.jboss.logmanager:jboss-logmanager:jar:3.2.0.Final:compile
|
||||
[INFO] | | | +- io.smallrye.common:smallrye-common-cpu:jar:2.15.0:compile
|
||||
[INFO] | | | +- io.smallrye.common:smallrye-common-expression:jar:2.15.0:compile
|
||||
[INFO] | | | +- io.smallrye.common:smallrye-common-net:jar:2.15.0:compile
|
||||
[INFO] | | | +- io.smallrye.common:smallrye-common-ref:jar:2.15.0:compile
|
||||
[INFO] | | | \- jakarta.json:jakarta.json-api:jar:2.1.3:compile
|
||||
[INFO] | | +- org.jboss.threads:jboss-threads:jar:3.9.2:compile
|
||||
[INFO] | | | \- io.smallrye.common:smallrye-common-function:jar:2.15.0:compile
|
||||
[INFO] | | +- org.slf4j:slf4j-api:jar:2.0.17:compile
|
||||
[INFO] | | +- org.jboss.slf4j:slf4j-jboss-logmanager:jar:2.0.2.Final:compile
|
||||
[INFO] | | +- org.wildfly.common:wildfly-common:jar:2.0.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-registry:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-bootstrap-runner:jar:3.31.1:compile
|
||||
[INFO] | | | +- io.quarkus:quarkus-classloader-commons:jar:3.31.1:compile
|
||||
[INFO] | | | \- io.smallrye.common:smallrye-common-io:jar:2.15.0:compile
|
||||
[INFO] | | \- io.quarkus:quarkus-fs-util:jar:1.3.0:compile
|
||||
[INFO] | \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.3:compile
|
||||
[INFO] +- io.quarkus:quarkus-rest:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus:quarkus-rest-common:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus.resteasy.reactive:resteasy-reactive-common:jar:3.31.1:compile
|
||||
[INFO] | | | +- io.quarkus.resteasy.reactive:resteasy-reactive-common-types:jar:3.31.1:compile
|
||||
[INFO] | | | \- org.reactivestreams:reactive-streams:jar:1.0.4:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-mutiny:jar:3.31.1:compile
|
||||
[INFO] | | | +- io.quarkus:quarkus-smallrye-context-propagation:jar:3.31.1:compile
|
||||
[INFO] | | | | \- io.smallrye:smallrye-context-propagation:jar:2.3.0:compile
|
||||
[INFO] | | | | +- io.smallrye:smallrye-context-propagation-api:jar:2.3.0:compile
|
||||
[INFO] | | | | \- io.smallrye:smallrye-context-propagation-storage:jar:2.3.0:compile
|
||||
[INFO] | | | \- io.smallrye.reactive:mutiny-smallrye-context-propagation:jar:3.1.0:compile
|
||||
[INFO] | | \- io.quarkus:quarkus-vertx:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-netty:jar:3.31.1:compile
|
||||
[INFO] | | | \- io.netty:netty-codec:jar:4.1.130.Final:compile
|
||||
[INFO] | | +- io.netty:netty-codec-haproxy:jar:4.1.130.Final:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-vertx-latebound-mdc-provider:jar:3.31.1:compile
|
||||
[INFO] | | \- io.smallrye:smallrye-fault-tolerance-vertx:jar:6.10.0:compile
|
||||
[INFO] | +- io.quarkus.resteasy.reactive:resteasy-reactive-vertx:jar:3.31.1:compile
|
||||
[INFO] | | +- io.vertx:vertx-web:jar:4.5.24:compile
|
||||
[INFO] | | | +- io.vertx:vertx-web-common:jar:4.5.24:compile
|
||||
[INFO] | | | +- io.vertx:vertx-auth-common:jar:4.5.24:compile
|
||||
[INFO] | | | \- io.vertx:vertx-bridge-common:jar:4.5.24:compile
|
||||
[INFO] | | +- io.smallrye.reactive:smallrye-mutiny-vertx-core:jar:3.21.4:compile
|
||||
[INFO] | | | +- io.smallrye.reactive:smallrye-mutiny-vertx-runtime:jar:3.21.4:compile
|
||||
[INFO] | | | \- io.smallrye.reactive:vertx-mutiny-generator:jar:3.21.4:compile
|
||||
[INFO] | | | \- io.vertx:vertx-codegen:jar:4.5.24:compile
|
||||
[INFO] | | +- io.quarkus.resteasy.reactive:resteasy-reactive:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus.vertx.utils:quarkus-vertx-utils:jar:3.31.1:compile
|
||||
[INFO] | | +- org.jboss.logging:commons-logging-jboss-logging:jar:1.0.0.Final:compile
|
||||
[INFO] | | \- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.4:compile
|
||||
[INFO] | | \- jakarta.activation:jakarta.activation-api:jar:2.1.4:compile
|
||||
[INFO] | +- io.quarkus:quarkus-vertx-http:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-security-runtime-spi:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-tls-registry:jar:3.31.1:compile
|
||||
[INFO] | | | +- io.quarkus:quarkus-tls-registry-spi:jar:3.31.1:compile
|
||||
[INFO] | | | \- io.smallrye.certs:smallrye-private-key-pem-parser:jar:0.9.2:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-credentials:jar:3.31.1:compile
|
||||
[INFO] | | +- io.smallrye.common:smallrye-common-vertx-context:jar:2.15.0:compile
|
||||
[INFO] | | +- io.quarkus.security:quarkus-security:jar:2.3.2:compile
|
||||
[INFO] | | +- io.smallrye.reactive:smallrye-mutiny-vertx-web:jar:3.21.4:compile
|
||||
[INFO] | | | +- io.smallrye.reactive:smallrye-mutiny-vertx-web-common:jar:3.21.4:compile
|
||||
[INFO] | | | +- io.smallrye.reactive:smallrye-mutiny-vertx-auth-common:jar:3.21.4:compile
|
||||
[INFO] | | | +- io.smallrye.reactive:smallrye-mutiny-vertx-bridge-common:jar:3.21.4:compile
|
||||
[INFO] | | | \- io.smallrye.reactive:smallrye-mutiny-vertx-uri-template:jar:3.21.4:compile
|
||||
[INFO] | | | \- io.vertx:vertx-uri-template:jar:4.5.24:compile
|
||||
[INFO] | | +- org.crac:crac:jar:1.5.0:compile
|
||||
[INFO] | | \- com.aayushatharva.brotli4j:brotli4j:jar:1.16.0:compile
|
||||
[INFO] | | +- com.aayushatharva.brotli4j:service:jar:1.16.0:compile
|
||||
[INFO] | | \- com.aayushatharva.brotli4j:native-osx-aarch64:jar:1.16.0:compile
|
||||
[INFO] | +- io.quarkus:quarkus-jsonp:jar:3.31.1:compile
|
||||
[INFO] | | \- org.eclipse.parsson:parsson:jar:1.1.7:compile
|
||||
[INFO] | \- io.quarkus:quarkus-virtual-threads:jar:3.31.1:compile
|
||||
[INFO] | \- io.vertx:vertx-core:jar:4.5.24:compile
|
||||
[INFO] | +- io.netty:netty-common:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-buffer:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-transport:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-handler:jar:4.1.130.Final:compile
|
||||
[INFO] | | \- io.netty:netty-transport-native-unix-common:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-handler-proxy:jar:4.1.130.Final:compile
|
||||
[INFO] | | \- io.netty:netty-codec-socks:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-codec-http:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-codec-http2:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-resolver:jar:4.1.130.Final:compile
|
||||
[INFO] | +- io.netty:netty-resolver-dns:jar:4.1.130.Final:compile
|
||||
[INFO] | | \- io.netty:netty-codec-dns:jar:4.1.130.Final:compile
|
||||
[INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.20.1:compile
|
||||
[INFO] +- io.quarkus:quarkus-rest-jackson:jar:3.31.1:compile
|
||||
[INFO] | \- io.quarkus:quarkus-rest-jackson-common:jar:3.31.1:compile
|
||||
[INFO] | \- io.quarkus:quarkus-jackson:jar:3.31.1:compile
|
||||
[INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.20.1:compile
|
||||
[INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.20.1:compile
|
||||
[INFO] | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.20.1:compile
|
||||
[INFO] +- io.quarkus:quarkus-hibernate-validator:jar:3.31.1:compile
|
||||
[INFO] | +- org.hibernate.validator:hibernate-validator:jar:9.1.0.Final:compile
|
||||
[INFO] | | +- jakarta.validation:jakarta.validation-api:jar:3.1.1:compile
|
||||
[INFO] | | \- com.fasterxml:classmate:jar:1.7.1:compile
|
||||
[INFO] | +- org.glassfish.expressly:expressly:jar:6.0.0:compile
|
||||
[INFO] | | \- jakarta.el:jakarta.el-api:jar:6.0.1:compile
|
||||
[INFO] | +- io.smallrye.config:smallrye-config-validator:jar:3.15.1:compile
|
||||
[INFO] | \- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.1.0:compile
|
||||
[INFO] +- io.quarkus:quarkus-config-yaml:jar:3.31.1:compile
|
||||
[INFO] | +- io.smallrye.config:smallrye-config-source-yaml:jar:3.15.1:compile
|
||||
[INFO] | | +- io.smallrye.config:smallrye-config-common:jar:3.15.1:compile
|
||||
[INFO] | | | \- io.smallrye.common:smallrye-common-classloader:jar:2.15.0:compile
|
||||
[INFO] | | \- io.smallrye.common:smallrye-common-constraint:jar:2.15.0:compile
|
||||
[INFO] | \- org.eclipse.microprofile.config:microprofile-config-api:jar:3.1:compile
|
||||
[INFO] +- io.quarkus:quarkus-jdbc-h2:jar:3.31.1:compile
|
||||
[INFO] | +- com.h2database:h2:jar:2.4.240:compile
|
||||
[INFO] | \- org.locationtech.jts:jts-core:jar:1.19.0:compile
|
||||
[INFO] +- io.quarkus:quarkus-liquibase:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus:quarkus-liquibase-common:jar:3.31.1:compile
|
||||
[INFO] | +- org.liquibase:liquibase-core:jar:4.33.0:compile
|
||||
[INFO] | | +- com.opencsv:opencsv:jar:5.11.2:compile
|
||||
[INFO] | | +- org.apache.commons:commons-collections4:jar:4.5.0:compile
|
||||
[INFO] | | +- org.apache.commons:commons-text:jar:1.15.0:compile
|
||||
[INFO] | | +- org.apache.commons:commons-lang3:jar:3.20.0:compile
|
||||
[INFO] | | \- commons-io:commons-io:jar:2.21.0:compile
|
||||
[INFO] | +- org.osgi:osgi.core:jar:6.0.0:compile
|
||||
[INFO] | +- org.yaml:snakeyaml:jar:2.5:compile
|
||||
[INFO] | +- io.quarkus:quarkus-jaxb:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-jaxp:jar:3.31.1:compile
|
||||
[INFO] | | \- org.glassfish.jaxb:jaxb-runtime:jar:4.0.6:compile
|
||||
[INFO] | | \- org.glassfish.jaxb:jaxb-core:jar:4.0.6:compile
|
||||
[INFO] | | +- org.eclipse.angus:angus-activation:jar:2.0.3:runtime
|
||||
[INFO] | | +- org.glassfish.jaxb:txw2:jar:4.0.6:compile
|
||||
[INFO] | | \- com.sun.istack:istack-commons-runtime:jar:4.1.2:compile
|
||||
[INFO] | +- io.quarkus:quarkus-agroal:jar:3.31.1:compile
|
||||
[INFO] | | +- io.quarkus:quarkus-datasource:jar:3.31.1:compile
|
||||
[INFO] | | +- io.agroal:agroal-api:jar:2.8:compile
|
||||
[INFO] | | +- io.agroal:agroal-narayana:jar:2.8:compile
|
||||
[INFO] | | | \- org.jboss:jboss-transaction-spi:jar:8.0.0.Final:compile
|
||||
[INFO] | | \- io.agroal:agroal-pool:jar:2.8:compile
|
||||
[INFO] | +- io.quarkus:quarkus-datasource-common:jar:3.31.1:compile
|
||||
[INFO] | \- io.quarkus:quarkus-narayana-jta:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus:quarkus-transaction-annotations:jar:3.31.1:compile
|
||||
[INFO] | +- io.smallrye:smallrye-context-propagation-jta:jar:2.3.0:compile
|
||||
[INFO] | +- io.smallrye.reactive:smallrye-reactive-converter-api:jar:3.0.3:compile
|
||||
[INFO] | +- io.smallrye.reactive:smallrye-reactive-converter-mutiny:jar:3.0.3:compile
|
||||
[INFO] | +- io.smallrye.reactive:mutiny-zero-flow-adapters:jar:1.1.1:compile
|
||||
[INFO] | +- org.jboss.narayana.jta:narayana-jta:jar:7.3.3.Final:compile
|
||||
[INFO] | | +- jakarta.resource:jakarta.resource-api:jar:2.1.0:compile
|
||||
[INFO] | | +- org.jboss.invocation:jboss-invocation:jar:2.0.0.Final:compile
|
||||
[INFO] | | \- org.eclipse.microprofile.reactive-streams-operators:microprofile-reactive-streams-operators-api:jar:3.0.1:compile
|
||||
[INFO] | \- org.jboss.narayana.jts:narayana-jts-integration:jar:7.3.3.Final:compile
|
||||
[INFO] +- io.quarkus:quarkus-hibernate-orm-panache:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus:quarkus-hibernate-orm:jar:3.31.1:compile
|
||||
[INFO] | | +- org.hibernate.orm:hibernate-core:jar:7.2.1.Final:compile
|
||||
[INFO] | | | +- org.hibernate.models:hibernate-models:jar:1.0.1:runtime
|
||||
[INFO] | | | \- org.antlr:antlr4-runtime:jar:4.13.2:compile
|
||||
[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.17.8:compile
|
||||
[INFO] | | +- org.hibernate.orm:hibernate-graalvm:jar:7.2.1.Final:compile
|
||||
[INFO] | | +- jakarta.persistence:jakarta.persistence-api:jar:3.2.0:compile
|
||||
[INFO] | | +- org.hibernate.local-cache:quarkus-local-cache:jar:0.5.0:compile
|
||||
[INFO] | | \- io.quarkus:quarkus-caffeine:jar:3.31.1:compile
|
||||
[INFO] | | \- com.github.ben-manes.caffeine:caffeine:jar:3.2.3:compile
|
||||
[INFO] | | \- com.google.errorprone:error_prone_annotations:jar:2.46.0:compile
|
||||
[INFO] | +- io.quarkus:quarkus-hibernate-orm-panache-common:jar:3.31.1:compile
|
||||
[INFO] | | \- io.quarkus:quarkus-panache-hibernate-common:jar:3.31.1:compile
|
||||
[INFO] | \- io.quarkus:quarkus-panache-common:jar:3.31.1:compile
|
||||
[INFO] +- io.quarkus:quarkus-rest-client-config:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus:quarkus-proxy-registry:jar:3.31.1:compile
|
||||
[INFO] | +- org.eclipse.microprofile.rest.client:microprofile-rest-client-api:jar:4.0:compile
|
||||
[INFO] | \- io.smallrye:jandex:jar:3.5.3:compile
|
||||
[INFO] +- io.quarkus:quarkus-rest-client-jackson:jar:3.31.1:compile
|
||||
[INFO] | +- io.quarkus.resteasy.reactive:resteasy-reactive-jackson:jar:3.31.1:compile
|
||||
[INFO] | | \- com.fasterxml.jackson.core:jackson-databind:jar:2.20.1:compile
|
||||
[INFO] | | \- com.fasterxml.jackson.core:jackson-annotations:jar:2.20:compile
|
||||
[INFO] | \- io.quarkus:quarkus-rest-client:jar:3.31.1:compile
|
||||
[INFO] | \- io.quarkus:quarkus-rest-client-jaxrs:jar:3.31.1:compile
|
||||
[INFO] | \- io.quarkus.resteasy.reactive:resteasy-reactive-client:jar:3.31.1:compile
|
||||
[INFO] | +- io.smallrye.stork:stork-api:jar:2.7.3:compile
|
||||
[INFO] | \- io.vertx:vertx-web-client:jar:4.5.24:compile
|
||||
[INFO] +- org.projectlombok:lombok:jar:1.18.42:provided
|
||||
[INFO] +- org.junit.jupiter:junit-jupiter:jar:5.10.3:test
|
||||
[INFO] | +- org.junit.jupiter:junit-jupiter-api:jar:6.0.2:test
|
||||
[INFO] | | +- org.opentest4j:opentest4j:jar:1.3.0:test
|
||||
[INFO] | | +- org.junit.platform:junit-platform-commons:jar:6.0.2:test
|
||||
[INFO] | | +- org.apiguardian:apiguardian-api:jar:1.1.2:test
|
||||
[INFO] | | \- org.jspecify:jspecify:jar:1.0.0:compile
|
||||
[INFO] | +- org.junit.jupiter:junit-jupiter-params:jar:6.0.2:test
|
||||
[INFO] | \- org.junit.jupiter:junit-jupiter-engine:jar:6.0.2:test
|
||||
[INFO] | \- org.junit.platform:junit-platform-engine:jar:6.0.2:test
|
||||
[INFO] \- org.mockito:mockito-junit-jupiter:jar:5.12.0:test
|
||||
[INFO] \- org.mockito:mockito-core:jar:5.21.0:test
|
||||
[INFO] +- net.bytebuddy:byte-buddy-agent:jar:1.17.8:test
|
||||
[INFO] \- org.objenesis:objenesis:jar:3.3:test
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 1.062 s
|
||||
[INFO] Finished at: 2026-02-21T19:02:53+01:00
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
Loading…
x
Reference in New Issue
Block a user