Skip to content
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@

- Passing unaltered sourceCode to PolyAPI for display within Canopy application.

- Fixed duplicate-field collisions by preprocessing JSON schemas to inject suffixed properties (e.g. order_id_1) into both properties and required before code generation, and enhanced NameHelper to preserve suffixes and special‐character mappings, eliminating “path not present” and “same field twice” errors.

### Changed

-
- PolyApiService.java: Replaced full-body buffering and Commons-IO parsing with a single BufferedInputStream using mark/reset for unified JSON/text/stream parsing and 1 KB error-preview logging.

- Added lombok dependency and plugin to parent-pom

### Fixed

Expand Down
39 changes: 0 additions & 39 deletions commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,6 @@
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.kjetland</groupId>
<artifactId>mbknor-jackson-jsonschema_2.12</artifactId>
Expand Down Expand Up @@ -137,25 +131,6 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

<!-- Release profile. -->
<profiles>
Expand All @@ -166,20 +141,6 @@
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
Expand Down
149 changes: 110 additions & 39 deletions commons/src/main/java/io/polyapi/commons/api/service/PolyApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import io.polyapi.commons.api.http.Response;
import io.polyapi.commons.api.json.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
Expand All @@ -24,7 +23,7 @@
import static java.util.function.Predicate.not;

/**
* Parent implementation class for all services that connec to the PolyAPI service.
* Parent implementation class for all services that connect to the PolyAPI service.
*/
@Slf4j
public class PolyApiService {
Expand All @@ -44,86 +43,158 @@ public <O> O get(String relativePath, Type expectedResponseType) {
return get(relativePath, new HashMap<>(), new HashMap<>(), expectedResponseType);
}

public <O> O get(String relativePath, Map<String, List<String>> headers, Map<String, List<String>> queryParams, Type expectedResponseType) {
public <O> O get(String relativePath,
Map<String, List<String>> headers,
Map<String, List<String>> queryParams,
Type expectedResponseType) {
return parsedCall(GET, relativePath, headers, queryParams, null, expectedResponseType);
}

public <I, O> O post(String relativePath, I body, Type expectedResponseType) {
return post(relativePath, new HashMap<>(), new HashMap<>(), body, expectedResponseType);
}

public <I, O> O post(String relativePath, Map<String, List<String>> headers, Map<String, List<String>> queryParams, I body, Type expectedResponseType) {
public <I, O> O post(String relativePath,
Map<String, List<String>> headers,
Map<String, List<String>> queryParams,
I body,
Type expectedResponseType) {
return parsedCall(POST, relativePath, headers, queryParams, body, expectedResponseType);
}

public <I> void patch(String relativePath, I body) {
parsedCall(PATCH, relativePath, new HashMap<>(), new HashMap<>(), body, Void.TYPE);
}

public <I> void patch(String relativePath, Map<String, List<String>> headers, Map<String, List<String>> queryParams, I body) {
public <I> void patch(String relativePath,
Map<String, List<String>> headers,
Map<String, List<String>> queryParams,
I body) {
parsedCall(PATCH, relativePath, headers, queryParams, body, Void.TYPE);
}

public void delete(String relativePath) {
delete(relativePath, new HashMap<>(), new HashMap<>(), null);
}


public <I> void delete(String relativePath, Map<String, List<String>> headers, Map<String, List<String>> queryParams, I body) {
public <I> void delete(String relativePath,
Map<String, List<String>> headers,
Map<String, List<String>> queryParams,
I body) {
parsedCall(DELETE, relativePath, headers, queryParams, body, Void.TYPE);
}

private <I, O> O parsedCall(HttpMethod method, String relativePath, Map<String, List<String>> headers, Map<String, List<String>> queryParams, I body, Type expectedResponseType) {
private <I, O> O parsedCall(HttpMethod method,
String relativePath,
Map<String, List<String>> headers,
Map<String, List<String>> queryParams,
I body,
Type expectedResponseType) {

Map<String, List<String>> allHeaders = new HashMap<>();
//allHeaders.put("Accept", List.of("application/json"));
allHeaders.put("Content-type", List.of("application/json"));
headers.forEach((key, value) -> allHeaders.put(key, value.stream().toList()));

Response response = callApi(method, relativePath, allHeaders, queryParams, jsonParser.toJsonInputStream(body));
Response response = callApi(
method,
relativePath,
allHeaders,
queryParams,
jsonParser.toJsonInputStream(body)
);

log.debug("Response is successful. Status code is {}.", response.statusCode());
log.debug("Parsing response.");
O result = Optional.of(expectedResponseType)
.filter(not(Void.TYPE::equals))
.map(type ->{
String contentType = response.headers().get("Content-type").stream().findFirst().orElseThrow();
O parsedResult;
log.debug("Content type is {}.", contentType);
log.debug("Type class is {}.", type.getClass());
log.debug("Type is {}.", type);
if (contentType.startsWith("application/json")) {
parsedResult = jsonParser.parseInputStream(response.body(), TypeVariable.class.isAssignableFrom(type.getClass()) ? Object.class : type);
} else {

final int PREVIEW = 1024;
byte[] previewBuf = new byte[PREVIEW];
int previewLen = 0;
BufferedInputStream bodyStream = new BufferedInputStream(response.body());

// mark & read first PREVIEW bytes for potential error logging
bodyStream.mark(PREVIEW);
try {
previewLen = bodyStream.read(previewBuf);
} catch (IOException ignored) {
}
try {
bodyStream.reset();
} catch (IOException ignored) {
}

try {
O parsed = Optional.of(expectedResponseType)
.filter(not(Void.TYPE::equals))
.map(type -> {
String contentType = response.headers()
.get("Content-type")
.stream()
.findFirst()
.orElse("application/json");

if (contentType.startsWith("application/json")) {
return jsonParser.parseInputStream(
bodyStream,
TypeVariable.class.isAssignableFrom(type.getClass())
? Object.class
: type
);
}

if (checkType(type, String.class) && contentType.startsWith("text/")) {
try {
parsedResult = (O)IOUtils.toString(response.body(), defaultCharset());
} catch (IOException e) {
throw new ParsingException("An error occurred while parsing the response.", e);
}
} else {
if (checkType(type, InputStream.class)) {
parsedResult = (O)response.body();
} else {
throw new UnsupportedContentTypeException(contentType, type);
@SuppressWarnings("unchecked")
O result = (O) new String(
bodyStream.readAllBytes(),
defaultCharset()
);
return result;
} catch (IOException ioe) {
throw new ParsingException("Could not read text response", ioe);
}
}
}
return parsedResult;
})
.orElse(null);
log.debug("Response parsed successfully.");
return result;

if (checkType(type, InputStream.class)) {
@SuppressWarnings("unchecked")
O result = (O) bodyStream;
return result;
}

throw new UnsupportedContentTypeException(contentType, type);
})
.orElse(null);

log.debug("Response parsed successfully.");
return parsed;

} catch (RuntimeException ex) {
String snippet = previewLen > 0
? new String(previewBuf, 0, previewLen, defaultCharset())
: "<no data>";
log.error("Failed to parse response from {} {} (first {} bytes):\n{}",
method, relativePath, previewLen, snippet);
throw ex;
}
}

private boolean checkType(Type type, Class<?> expectedClass) {
return (type.getClass().isAssignableFrom(Class.class) && Class.class.cast(type).isAssignableFrom(expectedClass)) || TypeVariable.class.isAssignableFrom(type.getClass());
return (type.getClass().isAssignableFrom(Class.class)
&& ((Class<?>) type).isAssignableFrom(expectedClass))
|| TypeVariable.class.isAssignableFrom(type.getClass());
}

private Response callApi(HttpMethod method, String relativePath, Map<String, List<String>> headers, Map<String, List<String>> queryParams, InputStream body) {
private Response callApi(HttpMethod method,
String relativePath,
Map<String, List<String>> headers,
Map<String, List<String>> queryParams,
InputStream body) {

Request request = client.prepareAuthenticatedRequest(host, port, method, relativePath)
.withHeaders(headers)
.withQueryParams(queryParams)
.withBody(body)
.build();

log.debug("Executing authenticated {} request with target {}", method, request.getUrl());
return client.send(request);
}
Expand Down
20 changes: 0 additions & 20 deletions library/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@
<version>3.9.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
Expand All @@ -71,20 +65,6 @@
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
Expand Down
21 changes: 21 additions & 0 deletions parent-pom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<junit.version>5.10.0</junit.version>
<slf4j.version>2.0.9</slf4j.version>
<powermock.version>2.0.9</powermock.version>
<lombok.version>1.18.38</lombok.version>
</properties>
<dependencies>

Expand Down Expand Up @@ -99,6 +100,12 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

<!-- Release profile. -->
Expand Down Expand Up @@ -162,6 +169,20 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
Expand Down
Loading