Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polish Roq exceptions #352

Merged
merged 2 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions blog/src/test/java/io/quarkiverse/roq/it/RoqBlogTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void testIndex() {
given().when().get("/").then().statusCode(200).body(containsString(
"A Static Site Generator to easily create a static website or blog using Quarkus super-powers."))
.body(containsString("Hello, world! I'm Roq")).body(containsString("minute(s) read"))
.body(containsString("Page 1 of")).body(containsString("2024 © ROQ"));
.body(containsString("Page 1 of")).body(containsString("© ROQ"));
}

@Test
Expand All @@ -29,15 +29,15 @@ public void testPosts() {
"A Static Site Generator to easily create a static website or blog using Quarkus super-powers."))
.body(containsString("<p>Hello folks,</p>"))
.body(containsString("<h1 class=\"page-title\">Welcome to Roq!</h1>"))
.body(containsString("2024 &copy; ROQ"));
.body(containsString("&copy; ROQ"));
}

@Test
public void testPostsAsciidoc() {
ValidatableResponse body = given().when().get("/posts/write-your-blog-posts-in-asciidoc").then().statusCode(200).body(containsString(
"Writing content is AsciiDoc format is an absolut no brainer"))
.body(containsString("<pre class=\"highlightjs highlight\"><code class=\"language-shell hljs\" data-lang=\"shell\">quarkus extension add io.quarkiverse.roq:quarkus-roq-plugin-asciidoc</code></pre>"))
.body(containsString("2024 &copy; ROQ"));
.body(containsString("&copy; ROQ"));
System.out.println(body.extract().body().asString());
}

Expand All @@ -46,7 +46,7 @@ public void testPage() {
given().when().get("/events").then().statusCode(200).body(containsString(
"A Static Site Generator to easily create a static website or blog using Quarkus super-powers."))
.body(containsString("<h2 class=\"event-title\">Roq 1.0 Beta</h2>"))
.body(containsString("2024 &copy; ROQ"));
.body(containsString("&copy; ROQ"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package io.quarkiverse.roq.data.deployment;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import io.quarkiverse.roq.data.deployment.exception.DataListBindingException;
import io.quarkiverse.roq.data.deployment.exception.DataReadingException;
import io.quarkiverse.roq.data.deployment.items.DataMappingBuildItem;
import io.quarkiverse.roq.data.deployment.items.RoqDataBeanBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
Expand All @@ -21,15 +25,17 @@ void convertDataMapping(List<DataMappingBuildItem> mappings,
parentClass = Class.forName(mapping.getParentType().toString(), false,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class %s not found".formatted(mapping.getParentType().toString()), e);
throw new IllegalStateException("Class %s not found".formatted(mapping.getParentType().toString()), e);
}

final Constructor<?> constructor;
try {
constructor = parentClass.getConstructor(List.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(
"@DataMapping for list should declare a constructor with a List<T> as unique parameter.", e);
throw new DataListBindingException(
"@DataMapping for list in %s should declare a constructor with a List<%s> as unique parameter"
.formatted(parentClass.getName(), mapping.getClassName()),
e);
}

try {
Expand All @@ -38,22 +44,28 @@ void convertDataMapping(List<DataMappingBuildItem> mappings,
final List<?> list = mapping.getConverter().convertToTypedList(mapping.getContent(), itemClass);
final Object data = constructor.newInstance(list);
beans.produce(new RoqDataBeanBuildItem(mapping.getName(), parentClass, data, mapping.isRecord()));
} catch (Exception e) {
throw new RuntimeException("Unable to convert data to a List<%s>.".formatted(mapping.getClassName()), e);
} catch (IOException e) {
throw new DataReadingException("Unable to read data in file %s as a List<%s>"
.formatted(mapping.sourceFile(), mapping.getClassName()), e);
} catch (ClassNotFoundException | InvocationTargetException | InstantiationException
| IllegalAccessException e) {
throw new RuntimeException(e);
}
} else {
Class<?> beanClass;
try {
beanClass = Class.forName(mapping.getClassName().toString(), false,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Class %s not found".formatted(mapping.getClassName().toString()), e);
throw new IllegalStateException("Class %s not found".formatted(mapping.getClassName().toString()), e);
}
try {
final Object data = mapping.getConverter().convertToType(mapping.getContent(), beanClass);
beans.produce(new RoqDataBeanBuildItem(mapping.getName(), beanClass, data, mapping.isRecord()));
} catch (Exception e) {
throw new RuntimeException("Unable to convert data to a %s.".formatted(mapping.getClassName()), e);
} catch (IOException e) {
throw new DataReadingException(
"Unable to convert data in file %s as a %s".formatted(mapping.sourceFile(), mapping.getClassName()),
e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
import org.jboss.logging.Logger;

import io.quarkiverse.roq.data.deployment.converters.DataConverterFinder;
import io.quarkiverse.roq.data.deployment.exception.DataConflictException;
import io.quarkiverse.roq.data.deployment.exception.DataConversionException;
import io.quarkiverse.roq.data.deployment.exception.DataMappingMismatchException;
import io.quarkiverse.roq.data.deployment.exception.DataScanningException;
import io.quarkiverse.roq.data.deployment.items.DataMappingBuildItem;
import io.quarkiverse.roq.data.deployment.items.RoqDataBuildItem;
import io.quarkiverse.roq.data.deployment.items.RoqDataJsonBuildItem;
Expand Down Expand Up @@ -49,7 +53,7 @@ void scanDataFiles(RoqProjectBuildItem roqProject,
}

} catch (IOException e) {
throw new RuntimeException(e);
throw new DataScanningException("Unable to scan data files", e);
}
}

Expand Down Expand Up @@ -78,8 +82,8 @@ void scanDataMappings(
if (config.enforceBean()) {
List<String> dataMappingErrors = collectDataMappingErrors(annotationMap.keySet(), dataJsonMap.keySet());
if (!dataMappingErrors.isEmpty()) {
throw new RuntimeException(
"Roq data is configured to enforce beans for data. Some data mapping and data files are not matching: %n%s"
throw new DataMappingMismatchException(
"Some data mappings and data files do not match: %n%s. Data mapping enforcement may be disabled in Roq."
.formatted(String.join(System.lineSeparator(), dataMappingErrors)));
}
}
Expand Down Expand Up @@ -107,6 +111,7 @@ void scanDataMappings(
final DotName type = methodInfo.parameterType(0).asParameterizedType().arguments().get(0).name();
dataMappingProducer.produce(new DataMappingBuildItem(
name,
item.sourceFile(),
className,
type, // need to get dynamically
item.getContent(),
Expand All @@ -116,6 +121,8 @@ void scanDataMappings(

final DataMappingBuildItem roqMapping = new DataMappingBuildItem(
name,
item.sourceFile(),

null,
className,
item.getContent(),
Expand All @@ -126,10 +133,12 @@ void scanDataMappings(
} else {
// Prepare mapping as JsonObject or JsonArray (we convert here to avoid one more step)
try {
final Object converted = roqDataBuildItem.converter().convert(roqDataBuildItem.getContent());
dataJsonProducer.produce(new RoqDataJsonBuildItem(name,
roqDataBuildItem.converter().convert(roqDataBuildItem.getContent())));
converted));
} catch (IOException e) {
throw new RuntimeException(e);
throw new DataConversionException(
"Unable to convert data file %s as an Object".formatted(roqDataBuildItem.sourceFile()), e);
}
}
}
Expand Down Expand Up @@ -174,7 +183,8 @@ public Collection<RoqDataBuildItem> scanDataFiles(RoqProjectBuildItem roqProject
(p, a) -> Files.isRegularFile(p) && isExtensionSupported(p))) {
pathStream.forEach(addRoqDataBuildItem(converter, watchedFilesProducer, path, items));
} catch (IOException e) {
throw new RuntimeException("Error while scanning data files on location %s".formatted(path.toString()), e);
throw new DataScanningException(
"Error while scanning data files on location: '%s'".formatted(path.toString()), e);
}
}
};
Expand All @@ -191,7 +201,7 @@ private static Consumer<Path> addRoqDataBuildItem(
return file -> {
var name = rootDir.relativize(file).toString().replaceAll("\\..*", "").replaceAll("/", "_");
if (items.containsKey(name)) {
throw new RuntimeException("Multiple data files found for name: " + name);
throw new DataConflictException("Multiple data files found for the name: '%s'.".formatted(name));
}
String filename = file.getFileName().toString();
if (Path.of("").getFileSystem().equals(file.getFileSystem())) {
Expand All @@ -202,7 +212,7 @@ private static Consumer<Path> addRoqDataBuildItem(

if (dataConverter != null) {
try {
items.put(name, new RoqDataBuildItem(name, Files.readAllBytes(file), dataConverter));
items.put(name, new RoqDataBuildItem(name, file, Files.readAllBytes(file), dataConverter));
} catch (IOException e) {
throw new UncheckedIOException("Error while decoding using %s converter: %s "
.formatted(filename, converter.getClass()), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public Object convert(byte[] content) throws IOException {
} else if (rootNode.isArray()) {
return new JsonArray(mapper.convertValue(rootNode, List.class));
} else {
throw new IOException("Unsupported YAML root element type: " + rootNode.getNodeType());
throw new IllegalStateException("Unsupported YAML root element type: " + rootNode.getNodeType());
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.quarkiverse.roq.data.deployment.exception;

public class DataConflictException extends RuntimeException {

public DataConflictException(String message) {
super(message);
}

public DataConflictException(String message, Throwable cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.quarkiverse.roq.data.deployment.exception;

import java.io.IOException;
import java.io.UncheckedIOException;

public class DataConversionException extends UncheckedIOException {

public DataConversionException(String message, IOException cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.quarkiverse.roq.data.deployment.exception;

public class DataListBindingException extends RuntimeException {

public DataListBindingException(String message) {
super(message);
}

public DataListBindingException(String message, Throwable cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

package io.quarkiverse.roq.data.deployment.exception;

public class DataMappingMismatchException extends RuntimeException {

public DataMappingMismatchException(String message) {
super(message);
}

public DataMappingMismatchException(String message, Throwable cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.quarkiverse.roq.data.deployment.exception;

import java.io.IOException;
import java.io.UncheckedIOException;

public class DataReadingException extends UncheckedIOException {
public DataReadingException(String message, IOException cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.quarkiverse.roq.data.deployment.exception;

import java.io.IOException;
import java.io.UncheckedIOException;

public class DataScanningException extends UncheckedIOException {
public DataScanningException(String message, IOException cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkiverse.roq.data.deployment.items;

import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;

Expand All @@ -15,6 +16,11 @@ public final class DataMappingBuildItem extends MultiBuildItem {
*/
private final String name;

/**
* Represent the source file.
*/
private final Path sourceFile;

/**
* Represents the {@link DotName} of parent type.
*/
Expand All @@ -40,16 +46,26 @@ public final class DataMappingBuildItem extends MultiBuildItem {
*/
private final boolean isRecord;

public DataMappingBuildItem(String name, DotName parentType, DotName className, byte[] content, DataConverter converter,
public DataMappingBuildItem(String name, Path sourceFile, DotName parentType, DotName className, byte[] content,
DataConverter converter,
boolean isRecord) {
this.name = name;
this.sourceFile = sourceFile;
this.parentType = parentType;
this.className = className;
this.content = content;
this.converter = converter;
this.isRecord = isRecord;
}

public Path sourceFile() {
return sourceFile;
}

public String name() {
return name;
}

public String getName() {
return name;
}
Expand Down Expand Up @@ -79,20 +95,17 @@ public byte[] getContent() {
}

@Override
public boolean equals(Object object) {
if (this == object)
return true;
if (object == null || getClass() != object.getClass())
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass())
return false;
DataMappingBuildItem that = (DataMappingBuildItem) object;
return isRecord == that.isRecord && Objects.equals(name, that.name) && Objects.equals(className, that.className)
&& Arrays.equals(content, that.content) && Objects.equals(converter, that.converter);
DataMappingBuildItem that = (DataMappingBuildItem) o;
return isRecord == that.isRecord && Objects.equals(name, that.name) && Objects.equals(sourceFile, that.sourceFile)
&& Objects.equals(parentType, that.parentType) && Objects.equals(className, that.className)
&& Objects.deepEquals(content, that.content) && Objects.equals(converter, that.converter);
}

@Override
public int hashCode() {
int result = Objects.hash(name, className, converter, isRecord);
result = 31 * result + Arrays.hashCode(content);
return result;
return Objects.hash(name, sourceFile, parentType, className, Arrays.hashCode(content), converter, isRecord);
}
}
Loading
Loading