Merge pull request #9 from sgoudham/main

Add support for more API endpoints
release
Hamothy 3 years ago committed by GitHub
commit b69edfcf2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
FROM maven:3.8.1-adoptopenjdk-11
MAINTAINER Goudham Suresh
RUN apt-get update && apt-get install -y \
gpg

83
Jenkinsfile vendored

@ -1,8 +1,7 @@
pipeline { pipeline {
agent { agent {
docker { dockerfile {
image "maven:3.8.1-adoptopenjdk-11" args '-u root'
args '-v /root/.m2:/root/.m2'
} }
} }
@ -14,56 +13,55 @@ pipeline {
NEXUS_CREDENTIAL_ID = 'e5582b32-3507-4e88-ab7c-d16d701c46e9' NEXUS_CREDENTIAL_ID = 'e5582b32-3507-4e88-ab7c-d16d701c46e9'
CODECOV_TOKEN = credentials('44a3c021-5cbb-4a6f-bea2-ae6c51d43038') CODECOV_TOKEN = credentials('44a3c021-5cbb-4a6f-bea2-ae6c51d43038')
GPG_SECRET_KEY = credentials('4dbfd4ed-bba4-44e0-8410-fbce1a9bba73')
GPG_OWNER_TRUST = credentials('8703bbe8-c099-481f-8337-1dce32d51771')
} }
stages { stages {
stage("Building") { stage("Import GPG Keys") {
steps { steps {
sh "mvn -B -DskipTests clean install" sh 'gpg --batch --import $GPG_SECRET_KEY'
sh 'gpg --import-ownertrust $GPG_OWNER_TRUST'
}
}
stage("Build") {
steps {
withCredentials([file(credentialsId: '076a36e8-d448-46fc-af11-7e7181a6cb99', variable: 'MAVEN_SETTINGS')]) {
sh 'mvn -s $MAVEN_SETTINGS -B -DskipTests clean package'
}
} }
} }
stage("Testing") { stage("Test") {
steps { steps {
sh "mvn test" sh "mvn test"
} }
post {
success {
echo "Generating Test Report..."
publishCoverage adapters: [jacocoAdapter('target/site/jacoco/jacoco.xml')]
echo "Sending Report to CodeCov..."
sh '''#!/bin/bash
bash <(curl -s https://codecov.io/bash) -t $CODECOV_TOKEN || echo "Codecov did not collect coverage reports"
'''
}
}
} }
stage("Deploying To Nexus") { stage("Deploy") {
when { when {
branch 'release' branch 'release'
} }
steps { steps {
script { withCredentials([file(credentialsId: '076a36e8-d448-46fc-af11-7e7181a6cb99', variable: 'MAVEN_SETTINGS')]) {
pom = readMavenPom file: "pom.xml"; sh 'mvn -s $MAVEN_SETTINGS -B -DskipTests clean deploy'
filesByGlob = findFiles(glob: "target/*.${pom.packaging}");
javadocsArtifact = filesByGlob[0].path;
jarWithSourcesArtifact = filesByGlob[1].path;
jarArtifact = filesByGlob[2].path;
if (fileExists(javadocsArtifact) && fileExists(jarWithSourcesArtifact) && fileExists(jarArtifact)) {
echo "*** File: ${javadocsArtifact}, group: ${pom.groupId}, packaging: ${pom.packaging}, version ${pom.version}";
echo "*** File: ${jarWithSourcesArtifact}, group: ${pom.groupId}, packaging: ${pom.packaging}, version ${pom.version}";
echo "*** File: ${jarArtifact}, group: ${pom.groupId}, packaging: ${pom.packaging}, version ${pom.version}";
nexusArtifactUploader(
nexusVersion: NEXUS_VERSION,
protocol: NEXUS_PROTOCOL,
nexusUrl: NEXUS_URL,
groupId: pom.groupId,
version: pom.version,
repository: NEXUS_REPOSITORY,
credentialsId: NEXUS_CREDENTIAL_ID,
artifacts: [
[artifactId: pom.artifactId, classifier: '', file: jarArtifact, type: pom.packaging],
[artifactId: pom.artifactId, classifier: 'javadocs', file: javadocsArtifact, type: pom.packaging],
[artifactId: pom.artifactId, classifier: 'sources', file: jarWithSourcesArtifact, type: pom.packaging],
[artifactId: pom.artifactId, classifier: '', file: "pom.xml", type: "pom"]
]
)
} else {
error "*** Files could not be found";
} }
} }
post {
success {
echo "Archiving Artifacts"
archiveArtifacts artifacts: 'target/*.jar'
}
} }
} }
} }
@ -71,17 +69,6 @@ pipeline {
post { post {
success { success {
echo "I'm Feeling Swag!" echo "I'm Feeling Swag!"
echo "Archiving Artifacts"
archiveArtifacts artifacts: 'target/*.jar'
echo "Generating Test Report..."
publishCoverage adapters: [jacocoAdapter('target/site/jacoco/jacoco.xml')]
echo "Sending Report to CodeCov..."
sh '''#!/bin/bash
bash <(curl -s https://codecov.io/bash) -t $CODECOV_TOKEN || echo "Codecov did not collect coverage reports"
'''
} }
failure { failure {
echo 'Not Very Swag :(' echo 'Not Very Swag :('

@ -1,23 +1,29 @@
<h1 align="center">MyWaifuWrapper | An Asynchronous Java API Wrapper for MyWaifuList</h1> [license]: https://img.shields.io/github/license/sgoudham/MyWaifuWrapper
[maven-central]: https://img.shields.io/maven-central/v/me.goudham/MyWaifuWrapper
<p align="center"> [build-status]: https://goudham.me/jenkins/job/MyWaifuWrapper/job/release/badge/icon
<img src="https://goudham.me/jenkins/job/MyWaifuWrapper/job/release/badge/icon"/> [codecov]: https://codecov.io/gh/sgoudham/MyWaifuWrapper/branch/release/graph/badge.svg?token=RxUDnCWnF0
<a href="https://codecov.io/gh/sgoudham/MyWaifuWrapper"> [issues]: https://img.shields.io/github/issues/sgoudham/MyWaifuWrapper?label=issues
<img src="https://codecov.io/gh/sgoudham/MyWaifuWrapper/branch/release/graph/badge.svg?token=RxUDnCWnF0"/> [pull-requests]: https://img.shields.io/github/issues-pr/sgoudham/MyWaifuWrapper
</a>
</p> ![license]
<p align="center"> ![maven-central]
<img src="https://img.shields.io/nexus/maven-goudham/org.goudham.me/MyWaifuWrapper?server=https%3A%2F%2Fgoudham.me"/> ![build-status]
<img src="https://img.shields.io/badge/project%20type-personal-blueviolet"/> ![codecov]
<img src="https://img.shields.io/github/last-commit/sgoudham/MyWaifuWrapper"/> ![issues]
<img src="https://img.shields.io/github/issues/sgoudham/MyWaifuWrapper?label=issues"/> ![pull-requests]
<img src="https://img.shields.io/github/issues-pr/sgoudham/MyWaifuWrapper"/>
</p> <h1 align="center">MyWaifuWrapper</h1>
<h2 align="center">An Asynchronous Java API Wrapper for MyWaifuList</h2>
# Summary # Summary
This is an Asynchronous API Wrapper for [MyWaifuList](https://mywaifulist.moe/dash) This is an Asynchronous API Wrapper for [MyWaifuList](https://mywaifulist.moe/dash)
# Disclaimer
Given that MyWaifuList is a primarily user-driven website and this API is currently in an Alpha state,
the data returned may not be fully complete and at its best quality
# Download # Download
TODO TODO

@ -4,10 +4,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.goudham.me</groupId> <groupId>me.goudham</groupId>
<artifactId>MyWaifuWrapper</artifactId> <artifactId>MyWaifuWrapper</artifactId>
<version>0.1.4</version> <version>0.1.1</version>
<packaging>jar</packaging>
<name>MyWaifuWrapper</name> <name>MyWaifuWrapper</name>
<description>An Asynchronous Java API Wrapper for MyWaifuList.</description>
<url>https://github.com/sgoudham/MyWaifuWrapper</url>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -15,6 +19,39 @@
<maven.compiler.target>11</maven.compiler.target> <maven.compiler.target>11</maven.compiler.target>
</properties> </properties>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<scm>
<connection>scm:git:git://github.com/sgoudham/MyWaifuWrapper.git</connection>
<developerConnection>scm:git:ssh://github.com:sgoudham/MyWaifuWrapper.git</developerConnection>
<url>https://github.com/sgoudham/MyWaifuWrapper/tree/main</url>
</scm>
<developers>
<developer>
<name>Goudham Suresh</name>
<email>sgoudham@gmail.com</email>
<organization>Github</organization>
<organizationUrl>https://github.com/sgoudham</organizationUrl>
</developer>
</developers>
<licenses>
<license>
<name>MIT License</name>
<url>https://www.opensource.org/licenses/mit-license.php</url>
</license>
</licenses>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
@ -91,6 +128,31 @@
<source>11</source> <source>11</source>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>

@ -1,14 +1,13 @@
package org.goudham.me; package me.goudham;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory; import me.goudham.domain.pagination.PaginationData;
import org.goudham.me.api.entity.series.FilteredSeries; import me.goudham.domain.series.Series;
import org.goudham.me.api.entity.series.Series; import me.goudham.domain.waifu.Waifu;
import org.goudham.me.api.entity.waifu.Waifu; import me.goudham.exception.APIMapperException;
import org.goudham.me.exception.APIMapperException;
import java.util.List; import java.util.List;
@ -24,84 +23,96 @@ class APIMapper {
} }
/** /**
* Honestly I don't really know how this works * Using the given {@code model}, {@link ObjectMapper} deserializes the given Json
* into a Java POJO
* *
* @param entity The actual class of the given entity. E.g {@link Waifu#getClass()} * @param result The result of the previous API response
* @param <T> The type of entity to be returned. E.g {@link Waifu} or {@link Series} * @param model The actual class of the given model. E.g {@link Waifu#getClass()}
* @return {@link JavaType} * @param <T> The type of model to be returned. E.g {@link Waifu} or {@link Series}
* @return {@link Response}
* @throws APIMapperException If {@link ObjectMapper} is not able to deserialize JSON to Java POJO properly
* *
*/ */
private <T> JavaType listOf(Class<T> entity) { <T> Response<T> deserialize(Result result, Class<T> model) throws APIMapperException {
return TypeFactory.defaultInstance().constructCollectionType(List.class, entity); Integer statusCode = result.getStatusCode();
String body = result.getBody();
T newModel = null;
if (statusCode == 200) {
try {
String data = getData(body);
newModel = objectMapper.readValue(data, model);
} catch (JsonProcessingException jpe) {
throwAPIMapperException(jpe);
}
}
return new Response<>(statusCode, body, newModel);
} }
/** /**
* Using the given {@code entity}, {@link ObjectMapper} deserializes the given Json * Using the given {@code model}, {@link ObjectMapper} deserializes the given Json
* into a Java POJO * into a Java POJO. This method enables support for retrieving {@link List} of models
* *
* @param result The result of the previous API response * @param result The result of the previous API response
* @param entity The actual class of the given entity. E.g {@link Waifu#getClass()} * @param model The actual class of the given model. E.g {@link Waifu#getClass()}
* @param <T> The type of entity to be returned. E.g {@link Waifu} or {@link Series} * @param <T> The type of model to be returned. E.g {@link Waifu} or {@link Series}
* @return {@link Response} * @return {@link Response}
* @throws APIMapperException If {@link ObjectMapper} is not able to deserialize JSON to Java POJO properly * @throws APIMapperException If {@link ObjectMapper} is not able to deserialize JSON to Java POJO properly
*
*/ */
<T> Response<T> deserialize(Result result, Class<T> entity) throws APIMapperException { <T> Response<List<T>> deserializeToList(Result result, JavaType model) throws APIMapperException {
Integer statusCode = result.getStatusCode(); Integer statusCode = result.getStatusCode();
String body = result.getBody(); String body = result.getBody();
T newEntity = null; List<T> listOfModels = null;
if (statusCode == 200) { if (statusCode == 200) {
try { try {
String data = getJsonTree(body); String data = getData(body);
newEntity = objectMapper.readValue(data, entity); listOfModels = objectMapper.readValue(data, model);
} catch (JsonProcessingException jpe) { } catch (JsonProcessingException jpe) {
throwAPIMapperException(jpe); throwAPIMapperException(jpe);
} }
} }
return new Response<>(statusCode, body, newEntity); return new Response<>(statusCode, body, listOfModels);
} }
/** /**
* Using the given {@code entity}, {@link ObjectMapper} deserializes the given Json * Using the given {@code model}, {@link ObjectMapper} deserializes the given Json
* into a Java POJO. This method enables support for retrieving {@link List} of entities * into a Java POJO. This method enables support for retrieving {@link PaginationData} of specific models
* *
* @param result The result of the previous API response * @param result The result of the previous API response
* @param entity The actual class of the given entity. E.g {@link Waifu#getClass()} * @param model The actual class of the given model. E.g {@link Waifu#getClass()}
* @param <T> List of entities to be returned. E.g {@link List} of {@link FilteredSeries} * @param <T> The type of model to be returned. E.g {@link Waifu} or {@link Series}
* @return {@link Response} * @return {@link Response}
* @throws APIMapperException If {@link ObjectMapper} is not able to deserialize JSON to Java POJO properly * @throws APIMapperException If {@link ObjectMapper} is not able to deserialize JSON to Java POJO properly
*/ */
<T> Response<List<T>> deserializeToList(Result result, Class<T> entity) throws APIMapperException { <T> Response<PaginationData<T>> deserializeToPaginationData(Result result, JavaType model) throws APIMapperException {
Integer statusCode = result.getStatusCode(); Integer statusCode = result.getStatusCode();
String body = result.getBody(); String body = result.getBody();
List<T> listOfEntity = null; PaginationData<T> newModel = null;
if (statusCode == 200) { if (statusCode == 200) {
try { try {
String data = getJsonTree(body); newModel = objectMapper.readValue(body, model);
listOfEntity = objectMapper.readValue(data, listOf(entity));
} catch (JsonProcessingException jpe) { } catch (JsonProcessingException jpe) {
throwAPIMapperException(jpe); throwAPIMapperException(jpe);
} }
} }
return new Response<>(statusCode, body, listOfEntity); return new Response<>(statusCode, body, newModel);
} }
/** /**
* Helper method for reducing duplicate code in {@code deserialize()} * Helper method for reducing duplicate code in {@code deserialize()}
* and {@code deserializeToList()} * and {@code deserializeToList()}
* <br>
* Returns the proper json data to deserialize
* *
* @param jsonBody jsonBody returned by the API * @param jsonBody jsonBody returned by the API
* @return {@link String} * @return {@link String} The proper json data to deserialize
* @throws JsonProcessingException If {@link ObjectMapper} is not able to * @throws JsonProcessingException If {@link ObjectMapper} is not able to
* read the given {@code jsonBody} * read the given {@code jsonBody}
*/ */
private String getJsonTree(String jsonBody) throws JsonProcessingException { private String getData(String jsonBody) throws JsonProcessingException {
JsonNode parent = objectMapper.readTree(jsonBody); JsonNode parent = objectMapper.readTree(jsonBody);
return parent.get("data").toString(); return parent.get("data").toString();
} }

@ -0,0 +1,35 @@
package me.goudham;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import me.goudham.domain.pagination.PaginationData;
import me.goudham.domain.series.Series;
import me.goudham.domain.waifu.Waifu;
import java.util.List;
/**
* Includes helper methods to use within {@link APIWrapper}
*
*/
class APIUtils {
/**
* @param model The actual class of the given model. E.g {@link Waifu#getClass()}
* @param <T> The type of model to be returned. E.g {@link Waifu} or {@link Series}
* @return {@link JavaType} of {@link List}
*
*/
static <T> JavaType listOf(Class<T> model) {
return TypeFactory.defaultInstance().constructCollectionType(List.class, model);
}
/**
* @param model The actual class of the given model. E.g {@link Waifu#getClass()}
* @param <T> The type of model to be returned. E.g {@link Waifu} or {@link Series}
* @return {@link JavaType} of {@link PaginationData}
*/
static <T> JavaType paginationData(Class<T> model) {
return TypeFactory.defaultInstance().constructParametricType(PaginationData.class, model);
}
}

@ -0,0 +1,168 @@
package me.goudham;
import me.goudham.domain.pagination.PaginationData;
import me.goudham.domain.series.FilteredSeries;
import me.goudham.domain.series.Series;
import me.goudham.domain.user.User;
import me.goudham.domain.user.UserList;
import me.goudham.domain.waifu.FilteredWaifu;
import me.goudham.domain.waifu.Waifu;
import me.goudham.domain.waifu.WaifuImage;
import me.goudham.exception.APIMapperException;
import me.goudham.exception.APIResponseException;
import me.goudham.util.Season;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import static me.goudham.APIUtils.listOf;
import static me.goudham.APIUtils.paginationData;
/**
* Returns API information to {@link MyWaifuClient}
*
*/
public class APIWrapper {
private final String version = "1.0";
private static final String host = "https://mywaifulist.moe/api/v1/";
private final String apiKey;
private final APIMapper apiMapper;
private final HttpClient httpClient;
private final Executor executor = Executors.newFixedThreadPool(10);
/**
* Instantiates an instance of {@link APIWrapper} to retrieve API Information.
* An instance of {@link APIMapper} is created to be able to {@code deserialize} JSON to
* Java objects
*
* @param apiKey API Key to authorise API request
* @param httpClient The underlying {@link HttpClient} to use for HttpRequests
*
*/
APIWrapper(String apiKey, HttpClient httpClient) {
this.apiKey = apiKey;
this.httpClient = httpClient;
apiMapper = new APIMapper();
}
/**
* Handles sending a request to the API asynchronously using {@link HttpRequest}
* and the underlying {@link HttpClient}
*
* @param param The end of the endpoint appended onto the host
* @return {@link Result}
* @throws APIResponseException If the {@link CompletableFuture Response}
* cannot be decoded or the thread was interrupted while waiting to receive the data
*
*/
private Result sendRequest(String param) throws APIResponseException {
CompletableFuture<Result> futureResult = CompletableFuture.supplyAsync(() -> {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(host + param))
.version(httpClient.version())
.timeout(Duration.ofSeconds(20))
.headers("Content-Type", "application/json", "apikey", apiKey)
.GET()
.build();
try {
return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException exp) {
exp.printStackTrace();
}
return null;
}, executor).thenApply(httpResponse -> new Result(httpResponse.statusCode(), httpResponse.body()));
try {
return futureResult.get();
} catch (InterruptedException | ExecutionException exp) {
throw new APIResponseException(exp.getMessage(), exp);
}
}
Response<Waifu> getWaifu(String waifuId) throws APIResponseException, APIMapperException {
Result waifuResult = sendRequest("waifu/" + waifuId);
return apiMapper.deserialize(waifuResult, Waifu.class);
}
Response<PaginationData<WaifuImage>> getWaifuImages(String waifuId, String pageNum) throws APIResponseException, APIMapperException {
Result waifuImagesResult = sendRequest("waifu/" + waifuId + "/images?page=" + pageNum);
return apiMapper.deserializeToPaginationData(waifuImagesResult, paginationData(WaifuImage.class));
}
Response<FilteredWaifu> getDailyWaifu() throws APIResponseException, APIMapperException {
Result dailyWaifuResult = sendRequest("meta/daily");
return apiMapper.deserialize(dailyWaifuResult, FilteredWaifu.class);
}
Response<FilteredWaifu> getRandomWaifu() throws APIResponseException, APIMapperException {
Result randomWaifuResult = sendRequest("meta/random");
return apiMapper.deserialize(randomWaifuResult, FilteredWaifu.class);
}
Response<List<FilteredSeries>> getSeasonalAnime() throws APIResponseException, APIMapperException {
Result seasonalAnimeResult = sendRequest("airing");
return apiMapper.deserializeToList(seasonalAnimeResult, listOf(FilteredSeries.class));
}
Response<List<FilteredWaifu>> getBestWaifus() throws APIResponseException, APIMapperException {
Result waifuResults = sendRequest("airing/best");
return apiMapper.deserializeToList(waifuResults, listOf(FilteredWaifu.class));
}
Response<List<FilteredWaifu>> getPopularWaifus() throws APIResponseException, APIMapperException {
Result waifuResults = sendRequest("airing/popular");
return apiMapper.deserializeToList(waifuResults, listOf(FilteredWaifu.class));
}
Response<List<FilteredWaifu>> getTrashWaifus() throws APIResponseException, APIMapperException {
Result waifuResults = sendRequest("airing/trash");
return apiMapper.deserializeToList(waifuResults, listOf(FilteredWaifu.class));
}
Response<Series> getSeries(String seriesId) throws APIResponseException, APIMapperException {
Result seriesResult = sendRequest("series/" + seriesId);
return apiMapper.deserialize(seriesResult, Series.class);
}
Response<PaginationData<FilteredSeries>> getSeriesByPage(String pageNum) throws APIResponseException, APIMapperException {
Result seriesPageResult = sendRequest("series?page=" + pageNum);
return apiMapper.deserializeToPaginationData(seriesPageResult, paginationData(FilteredSeries.class));
}
Response<List<FilteredSeries>> getAllSeries(Season season, Integer year) throws APIResponseException, APIMapperException {
Result allSeriesResult = sendRequest("airing/" + season.getSeason() + "/" + year);
return apiMapper.deserializeToList(allSeriesResult, listOf(FilteredSeries.class));
}
Response<List<FilteredWaifu>> getSeriesWaifus(String seriesId) throws APIResponseException, APIMapperException {
Result allWaifusFromSeriesResults = sendRequest("series/" + seriesId + "/waifus");
return apiMapper.deserializeToList(allWaifusFromSeriesResults, listOf(FilteredWaifu.class));
}
Response<User> getUserProfile(String userId) throws APIResponseException, APIMapperException {
Result userProfileResult = sendRequest("user/" + userId);
return apiMapper.deserialize(userProfileResult, User.class);
}
Response<List<UserList>> getUserLists(String userId) throws APIResponseException, APIMapperException {
Result userProfileResult = sendRequest("user/" + userId + "/lists");
return apiMapper.deserializeToList(userProfileResult, listOf(UserList.class));
}
Response<UserList> getUserList(String userId, String listId) throws APIResponseException, APIMapperException {
Result userProfileResult = sendRequest("user/" + userId + "/lists/" + listId);
return apiMapper.deserialize(userProfileResult, UserList.class);
}
}

@ -0,0 +1,214 @@
package me.goudham;
import me.goudham.domain.pagination.PaginationData;
import me.goudham.domain.series.FilteredSeries;
import me.goudham.domain.series.Series;
import me.goudham.domain.user.User;
import me.goudham.domain.user.UserList;
import me.goudham.domain.waifu.FilteredWaifu;
import me.goudham.domain.waifu.Waifu;
import me.goudham.domain.waifu.WaifuImage;
import me.goudham.exception.APIMapperException;
import me.goudham.exception.APIResponseException;
import me.goudham.util.Season;
import org.jetbrains.annotations.NotNull;
import javax.net.ssl.SSLParameters;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.ProxySelector;
import java.net.http.HttpClient;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.Executor;
/**
* A MyWaifuClient, the underlying client used for making requests is {@link HttpClient}
*
*
* <p> Main entry point for retrieving information from MyWaifuList.</p>
* <p> {@link APIWrapper} is utilised to make the API requests </p>
*/
public class MyWaifuClient {
private final APIWrapper APIWrapper;
/**
* Creates an instance of {@link MyWaifuClient}
*
* <p>See <a href="https://mywaifulist.docs.stoplight.io/">MyWaifuList</a> for obtaining an API Key</p>
* @param apiKey API Key to authorise API request
* @param httpClient The underlying {@link HttpClient} to use for HttpRequests
*
*/
MyWaifuClient(@NotNull String apiKey, @NotNull HttpClient httpClient) {
APIWrapper = new APIWrapper(apiKey, httpClient);
}
/**
* Creates an instance of {@link MyWaifuClient} with default {@link HttpClient} settings
*
* @param apiKey API Key to authorise API request
* @return {@link MyWaifuClient}
*/
public static MyWaifuClient createDefault(@NotNull String apiKey) {
HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build();
return new MyWaifuClient(apiKey, httpClient);
}
/**
* Retrieves information about the {@link Waifu} specified by the given slug
*
* @param slug The slug of the {@link Waifu}
* @return {@link Response}
* @throws APIResponseException If {@link APIWrapper} could not return information properly
* @throws APIMapperException If {@link APIMapper} could not correctly {@code deserialize} model
*
*/
public Response<Waifu> getWaifu(@NotNull String slug) throws APIResponseException, APIMapperException {
return APIWrapper.getWaifu(slug);
}
/**
* Retrieves information about the {@link Waifu} specified by the given id
*
* @param id The id of the {@link Waifu}
* @return {@link Response}
* @throws APIResponseException If {@link APIWrapper} could not return information properly
* @throws APIMapperException If {@link APIMapper} could not correctly {@code deserialize} model
*
*/
public Response<Waifu> getWaifu(@NotNull Integer id) throws APIResponseException, APIMapperException {
return APIWrapper.getWaifu(String.valueOf(id));
}
public Response<PaginationData<WaifuImage>> getWaifuImages(@NotNull Integer id, @NotNull Integer pageNum) throws APIResponseException, APIMapperException {
return APIWrapper.getWaifuImages(String.valueOf(id), String.valueOf(pageNum));
}
public Response<FilteredWaifu> getDailyWaifu() throws APIResponseException, APIMapperException {
return APIWrapper.getDailyWaifu();
}
public Response<FilteredWaifu> getRandomWaifu() throws APIResponseException, APIMapperException {
return APIWrapper.getRandomWaifu();
}
public Response<List<FilteredSeries>> getSeasonalAnime() throws APIMapperException, APIResponseException {
return APIWrapper.getSeasonalAnime();
}
public Response<List<FilteredWaifu>> getBestWaifus() throws APIMapperException, APIResponseException {
return APIWrapper.getBestWaifus();
}
public Response<List<FilteredWaifu>> getPopularWaifus() throws APIMapperException, APIResponseException {
return APIWrapper.getPopularWaifus();
}
public Response<List<FilteredWaifu>> getTrashWaifus() throws APIMapperException, APIResponseException {
return APIWrapper.getTrashWaifus();
}
public Response<Series> getSeries(@NotNull String slug) throws APIMapperException, APIResponseException {
return APIWrapper.getSeries(slug);
}
public Response<Series> getSeries(@NotNull Integer id) throws APIMapperException, APIResponseException {
return APIWrapper.getSeries(String.valueOf(id));
}
public Response<PaginationData<FilteredSeries>> getSeriesByPage(@NotNull Integer pageNum) throws APIMapperException, APIResponseException {
return APIWrapper.getSeriesByPage(String.valueOf(pageNum));
}
public Response<List<FilteredSeries>> getAllSeries(@NotNull Season season, @NotNull Integer year) throws APIResponseException, APIMapperException {
return APIWrapper.getAllSeries(season, year);
}
public Response<List<FilteredWaifu>> getSeriesWaifus(@NotNull String slug) throws APIMapperException, APIResponseException {
return APIWrapper.getSeriesWaifus(slug);
}
public Response<List<FilteredWaifu>> getSeriesWaifus(@NotNull Integer id) throws APIMapperException, APIResponseException {
return APIWrapper.getSeriesWaifus(String.valueOf(id));
}
public Response<User> getUserProfile(@NotNull Integer id) throws APIMapperException, APIResponseException {
return APIWrapper.getUserProfile(String.valueOf(id));
}
public Response<List<UserList>> getUserLists(@NotNull Integer id) throws APIMapperException, APIResponseException {
return APIWrapper.getUserLists(String.valueOf(id));
}
public Response<UserList> getUserList(@NotNull Integer userId, @NotNull Integer listId) throws APIMapperException, APIResponseException {
return APIWrapper.getUserList(String.valueOf(userId), String.valueOf(listId));
}
/**
* Builder for {@link MyWaifuClient}
*
*/
public static class Builder {
private final String apiKey;
private final HttpClient.Builder httpClientBuilder = HttpClient.newBuilder();
public Builder(@NotNull String apiKey) {
this.apiKey = apiKey;
}
public Builder withCookieHandler(CookieHandler cookieHandler) {
httpClientBuilder.cookieHandler(cookieHandler);
return this;
}
public Builder withConnectTimeout(@NotNull Duration duration) {
httpClientBuilder.connectTimeout(duration);
return this;
}
public Builder withSslParameters(@NotNull SSLParameters sslParameters) {
httpClientBuilder.sslParameters(sslParameters);
return this;
}
public Builder withExecutor(@NotNull Executor executor) {
httpClientBuilder.executor(executor);
return this;
}
public Builder withFollowRedirects(@NotNull HttpClient.Redirect policy) {
httpClientBuilder.followRedirects(policy);
return this;
}
public Builder withVersion(@NotNull HttpClient.Version version) {
httpClientBuilder.version(version);
return this;
}
public Builder withPriority(int priority) {
httpClientBuilder.priority(priority);
return this;
}
public Builder withProxy(@NotNull ProxySelector proxySelector) {
httpClientBuilder.proxy(proxySelector);
return this;
}
public Builder withAuthenticator(@NotNull Authenticator authenticator) {
httpClientBuilder.authenticator(authenticator);
return this;
}
public MyWaifuClient build() {
return new MyWaifuClient(apiKey, httpClientBuilder.build());
}
}
}

@ -0,0 +1,41 @@
package me.goudham;
import me.goudham.domain.series.Series;
import me.goudham.domain.waifu.Waifu;
/**
* This is returned to the User when called by methods in {@link MyWaifuClient}.
* E.g {@link MyWaifuClient#getWaifu(Integer)}
* <br>
* Given a successful response, {@link #model} will be populated with the requested model.
* <br>
* No matter successful or unsuccessful response, {@link #statusCode} and {@link #body}
* will be populated to ensure the user has all the information for debugging or extra information within
* the {@link #body}
*
* @param <T> The type of model to be returned. E.g {@link Waifu} or {@link Series}
*
*/
public class Response<T> {
private final T model;
private final Integer statusCode;
private final String body;
Response(Integer statusCode, String body, T model) {
this.statusCode = statusCode;
this.body = body;
this.model = model;
}
public T getModel() {
return model;
}
public Integer getStatusCode() {
return statusCode;
}
public String getBody() {
return body;
}
}

@ -1,5 +1,11 @@
package org.goudham.me; package me.goudham;
import java.net.http.HttpRequest;
/**
* Represents a Result from a {@link HttpRequest} with the resulting
* {@code statusCode} and {@code body}
*/
class Result { class Result {
private final Integer statusCode; private final Integer statusCode;
private final String body; private final String body;

@ -1,8 +1,9 @@
package org.goudham.me.api.entity; package me.goudham.domain;
import javax.annotation.processing.Generated; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.Objects; import java.util.Objects;
@ -24,7 +25,6 @@ import java.util.Objects;
"name", "name",
"original_name" "original_name"
}) })
@Generated("jsonschema2pojo")
public class Studio { public class Studio {
Studio() { } Studio() { }

@ -0,0 +1,125 @@
package me.goudham.domain.pagination;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.Objects;
/**
* {@link Links}
* <p>Contains gallery API links for {@link Meta}</p>
*
* <p> Fields included are: </p>
* <ul>
* <li>{@link String first}</li>
* <li>{@link String last}</li>
* <li>{@link String next}</li>
* <li>{@link String prev}</li>
* </ul>
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"first",
"last",
"next",
"prev"
})
public class Links {
/**
* First page of the gallery
*
*/
@JsonProperty("first")
@JsonPropertyDescription("First page of the gallery")
private String first;
/**
* Last page of the gallery
*
*/
@JsonProperty("last")
@JsonPropertyDescription("Last page of the gallery")
private String last;
/**
* Next page of the gallery
*
*/
@JsonProperty("next")
@JsonPropertyDescription("Next page of the gallery")
private String next;
/**
* Previous page of the gallery
*
*/
@JsonProperty("prev")
@JsonPropertyDescription("Previous page of the gallery")
private String prev;
@JsonProperty("first")
public String getFirst() {
return first;
}
@JsonProperty("first")
public void setFirst(String first) {
this.first = first;
}
@JsonProperty("last")
public String getLast() {
return last;
}
@JsonProperty("last")
public void setLast(String last) {
this.last = last;
}
@JsonProperty("next")
public String getNext() {
return next;
}
@JsonProperty("next")
public void setNext(String next) {
this.next = next;
}
@JsonProperty("prev")
public String getPrev() {
return prev;
}
@JsonProperty("prev")
public void setPrev(String prev) {
this.prev = prev;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Links links = (Links) o;
return Objects.equals(first, links.first) && Objects.equals(last, links.last) && Objects.equals(next, links.next) && Objects.equals(prev, links.prev);
}
@Override
public int hashCode() {
return Objects.hash(first, last, next, prev);
}
@Override
public String toString() {
return "Links{" +
"first='" + first + '\'' +
", last='" + last + '\'' +
", next='" + next + '\'' +
", prev='" + prev + '\'' +
'}';
}
}

@ -0,0 +1,177 @@
package me.goudham.domain.pagination;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.Objects;
/**
* {@link Meta}
* <p>Contains standard Pagination data from the API</p>
*
* <p> Fields included are: </p>
* <ul>
* <li>{@link Integer currentPage}</li>
* <li>{@link Integer from}</li>
* <li>{@link Integer lastPage}</li>
* <li>{@link String path}</li>
* <li>{@link Integer perPage}</li>
* <li>{@link Integer to}</li>
* <li>{@link Integer total}</li>
* </ul>
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"current_page",
"from",
"last_page",
"path",
"per_page",
"to",
"total"
})
public class Meta {
/**
* Current requested page
*
*/
@JsonProperty("current_page")
@JsonPropertyDescription("Current requested page")
private Integer currentPage;
/**
* Starting gallery image number
*
*/
@JsonProperty("from")
@JsonPropertyDescription("Starting gallery image number")
private Integer from;
/**
* Last available page
*
*/
@JsonProperty("last_page")
@JsonPropertyDescription("Last available page")
private Integer lastPage;
/**
* API url for gallery
*
*/
@JsonProperty("path")
@JsonPropertyDescription("API url for gallery")
private String path;
/**
* Total number of items per page
*
*/
@JsonProperty("per_page")
@JsonPropertyDescription("Total number of items per page")
private Integer perPage;
/**
* Last gallery image number
*
*/
@JsonProperty("to")
@JsonPropertyDescription("Last gallery image number")
private Integer to;
/**
* Total number of items within the gallery
*
*/
@JsonProperty("total")
@JsonPropertyDescription("Total number of items")
private Integer total;
@JsonProperty("current_page")
public Integer getCurrentPage() {
return currentPage;
}
@JsonProperty("current_page")
public void setCurrentPage(Integer currentPage) {
this.currentPage = currentPage;
}
@JsonProperty("from")
public Integer getFrom() { return from; }
@JsonProperty("from")
public void setFrom(Integer from) { this.from = from; }
@JsonProperty("last_page")
public Integer getLastPage() {
return lastPage;
}
@JsonProperty("last_page")
public void setLastPage(Integer lastPage) {
this.lastPage = lastPage;
}
@JsonProperty("path")
public String getPath() { return path; }
@JsonProperty("path")
public void setPath(String path) { this.path = path; }
@JsonProperty("per_page")
public Integer getPerPage() {
return perPage;
}
@JsonProperty("per_page")
public void setPerPage(Integer perPage) {
this.perPage = perPage;
}
@JsonProperty("to")
public Integer getTo() { return to; }
@JsonProperty("to")
public void setTo(Integer to) { this.to = to; }
@JsonProperty("total")
public Integer getTotal() {
return total;
}
@JsonProperty("total")
public void setTotal(Integer total) {
this.total = total;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Meta meta = (Meta) o;
return Objects.equals(currentPage, meta.currentPage) && Objects.equals(from, meta.from) && Objects.equals(lastPage, meta.lastPage) && Objects.equals(path, meta.path) && Objects.equals(perPage, meta.perPage) && Objects.equals(to, meta.to) && Objects.equals(total, meta.total);
}
@Override
public int hashCode() {
return Objects.hash(currentPage, from, lastPage, path, perPage, to, total);
}
@Override
public String toString() {
return "Meta{" +
"currentPage=" + currentPage +
", from=" + from +
", lastPage=" + lastPage +
", path=" + path +
", perPage=" + perPage +
", to=" + to +
", total=" + total +
'}';
}
}

@ -0,0 +1,84 @@
package me.goudham.domain.pagination;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.List;
/**
* {@link PaginationData}
* <p>Contains standard Pagination data from the API including images</p>
*
* <p> Fields included are: </p>
* <ul>
* <li>{@link Object data}</li>
* <li>{@link Links links}</li>
* <li>{@link Meta meta}</li>
* </ul>
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"data",
"links",
"meta"
})
public class PaginationData<T> {
/**
* Data returned from the gallery
*
*/
@JsonProperty("data")
@JsonPropertyDescription("Data returned from the gallery")
private List<T> data;
/**
* {@link Links} to other data within the gallery
*
*/
@JsonProperty("links")
@JsonPropertyDescription("Links to other data within the gallery")
private Links links;
/**
* Extra pagination information
*
*/
@JsonProperty("meta")
@JsonPropertyDescription("Extra pagination information")
private Meta meta;
@JsonProperty("data")
public List<T> getData() {
return data;
}
@JsonProperty("data")
public void setData(List<T> data) {
this.data = data;
}
@JsonProperty("links")
public Links getLinks() {
return links;
}
@JsonProperty("links")
public void setLinks(Links links) {
this.links = links;
}
@JsonProperty("meta")
public Meta getMeta() {
return meta;
}
@JsonProperty("meta")
public void setMeta(Meta meta) {
this.meta = meta;
}
}

@ -1,6 +1,4 @@
package org.goudham.me.api.entity.series; package me.goudham.domain.series;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
@ -41,7 +39,6 @@ import java.util.Objects;
"url", "url",
"id" "id"
}) })
@Generated("jsonschema2pojo")
public class FilteredSeries { public class FilteredSeries {
/** /**
* Full name, in English. * Full name, in English.
@ -218,12 +215,12 @@ public class FilteredSeries {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
FilteredSeries that = (FilteredSeries) o; FilteredSeries that = (FilteredSeries) o;
return Objects.equals(name, that.name) && Objects.equals(originalName, that.originalName) && Objects.equals(romajiName, that.romajiName) && Objects.equals(slug, that.slug) && Objects.equals(description, that.description) && Objects.equals(url, that.url) && Objects.equals(id, that.id); return Objects.equals(name, that.name) && Objects.equals(originalName, that.originalName) && Objects.equals(relevance, that.relevance) && Objects.equals(romajiName, that.romajiName) && Objects.equals(slug, that.slug) && Objects.equals(type, that.type) && Objects.equals(description, that.description) && Objects.equals(displayPicture, that.displayPicture) && Objects.equals(url, that.url) && Objects.equals(id, that.id);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(name, originalName, romajiName, slug, description, url, id); return Objects.hash(name, originalName, relevance, romajiName, slug, type, description, displayPicture, url, id);
} }
@Override @Override
@ -231,9 +228,12 @@ public class FilteredSeries {
return "FilteredSeries{" + return "FilteredSeries{" +
"name='" + name + '\'' + "name='" + name + '\'' +
", originalName='" + originalName + '\'' + ", originalName='" + originalName + '\'' +
", relevance=" + relevance +
", romajiName='" + romajiName + '\'' + ", romajiName='" + romajiName + '\'' +
", slug='" + slug + '\'' + ", slug='" + slug + '\'' +
", type='" + type + '\'' +
", description='" + description + '\'' + ", description='" + description + '\'' +
", displayPicture='" + displayPicture + '\'' +
", url='" + url + '\'' + ", url='" + url + '\'' +
", id=" + id + ", id=" + id +
'}'; '}';

@ -1,10 +1,8 @@
package org.goudham.me.api.entity.series; package me.goudham.domain.series;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.annotation.*;
import org.goudham.me.api.entity.Studio; import me.goudham.domain.Studio;
import org.goudham.me.api.entity.waifu.Waifu; import me.goudham.domain.waifu.Waifu;
import java.util.Objects; import java.util.Objects;
@ -26,7 +24,7 @@ import java.util.Objects;
* <li>{@link String displayPicture}</li> * <li>{@link String displayPicture}</li>
* <li>{@link String url}</li> * <li>{@link String url}</li>
* <li>{@link Studio}</li> * <li>{@link Studio}</li>
* <li>{@link String} type</li> * <li>{@link String type}</li>
* <li>{@link Integer id}</li> * <li>{@link Integer id}</li>
* </ul> * </ul>
* *
@ -48,7 +46,7 @@ import java.util.Objects;
"type", "type",
"id" "id"
}) })
@Generated("jsonschema2pojo") @JsonIgnoreProperties(ignoreUnknown = true)
public class Series { public class Series {
/** /**
* Full Name (in English) * Full Name (in English)
@ -302,12 +300,12 @@ public class Series {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Series series = (Series) o; Series series = (Series) o;
return Objects.equals(name, series.name) && Objects.equals(originalName, series.originalName) && Objects.equals(romajiName, series.romajiName) && Objects.equals(description, series.description) && Objects.equals(slug, series.slug) && Objects.equals(releaseDate, series.releaseDate) && Objects.equals(airingStart, series.airingStart) && Objects.equals(airingEnd, series.airingEnd) && Objects.equals(episodeCount, series.episodeCount) && Objects.equals(displayPicture, series.displayPicture) && Objects.equals(url, series.url) && Objects.equals(studio, series.studio) && Objects.equals(id, series.id); return Objects.equals(name, series.name) && Objects.equals(originalName, series.originalName) && Objects.equals(romajiName, series.romajiName) && Objects.equals(description, series.description) && Objects.equals(slug, series.slug) && Objects.equals(releaseDate, series.releaseDate) && Objects.equals(airingStart, series.airingStart) && Objects.equals(airingEnd, series.airingEnd) && Objects.equals(episodeCount, series.episodeCount) && Objects.equals(displayPicture, series.displayPicture) && Objects.equals(url, series.url) && Objects.equals(studio, series.studio) && Objects.equals(type, series.type) && Objects.equals(id, series.id);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(name, originalName, romajiName, description, slug, releaseDate, airingStart, airingEnd, episodeCount, displayPicture, url, studio, id); return Objects.hash(name, originalName, romajiName, description, slug, releaseDate, airingStart, airingEnd, episodeCount, displayPicture, url, studio, type, id);
} }
@Override @Override
@ -322,9 +320,10 @@ public class Series {
", airingStart='" + airingStart + '\'' + ", airingStart='" + airingStart + '\'' +
", airingEnd='" + airingEnd + '\'' + ", airingEnd='" + airingEnd + '\'' +
", episodeCount=" + episodeCount + ", episodeCount=" + episodeCount +
", image='" + displayPicture + '\'' + ", displayPicture='" + displayPicture + '\'' +
", url='" + url + '\'' + ", url='" + url + '\'' +
", studio=" + studio + ", studio=" + studio +
", type='" + type + '\'' +
", id=" + id + ", id=" + id +
'}'; '}';
} }

@ -1,13 +1,10 @@
package org.goudham.me.api.entity.user; package me.goudham.domain.user;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import org.goudham.me.api.entity.waifu.Waifu;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import me.goudham.domain.waifu.Waifu;
import java.util.Objects; import java.util.Objects;
@ -27,7 +24,6 @@ import java.util.Objects;
"id", "id",
"name" "name"
}) })
@Generated("jsonschema2pojo")
public class Creator { public class Creator {
/** /**
@ -35,14 +31,14 @@ public class Creator {
* *
*/ */
@JsonProperty("id") @JsonProperty("id")
@JsonPropertyDescription("") @JsonPropertyDescription("Creator ID")
private Integer id; private Integer id;
/** /**
* {@link Creator} Name * {@link Creator} Name
*/ */
@JsonProperty("name") @JsonProperty("name")
@JsonPropertyDescription("") @JsonPropertyDescription("Creator Name")
private String name; private String name;
@JsonProperty("id") @JsonProperty("id")

@ -1,13 +1,12 @@
package org.goudham.me.api.entity.user; package me.goudham.domain.user;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription; import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.goudham.me.api.entity.series.Series; import me.goudham.domain.series.Series;
import javax.annotation.processing.Generated;
import java.util.Objects; import java.util.Objects;
/** /**
@ -28,7 +27,6 @@ import java.util.Objects;
"slug", "slug",
"series" "series"
}) })
@Generated("jsonschema2pojo")
public class TrueLove { public class TrueLove {
/** /**
* Name of {@link TrueLove} * Name of {@link TrueLove}

@ -1,12 +1,7 @@
package org.goudham.me.api.entity.user; package me.goudham.domain.user;
import javax.annotation.processing.Generated; import com.fasterxml.jackson.annotation.*;
import me.goudham.domain.waifu.Waifu;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.goudham.me.api.entity.waifu.Waifu;
import java.util.Objects; import java.util.Objects;
@ -17,6 +12,7 @@ import java.util.Objects;
* *
* <p> Fields included are: </p> * <p> Fields included are: </p>
* <ul> * <ul>
* <li>{@link String avatar}</li>
* <li>{@link Integer id}</li> * <li>{@link Integer id}</li>
* <li>{@link String name}</li> * <li>{@link String name}</li>
* <li>{@link String twitter}</li> * <li>{@link String twitter}</li>
@ -30,6 +26,7 @@ import java.util.Objects;
*/ */
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ @JsonPropertyOrder({
"avatar",
"id", "id",
"name", "name",
"twitter", "twitter",
@ -39,13 +36,20 @@ import java.util.Objects;
"waifus_trashed", "waifus_trashed",
"true_love" "true_love"
}) })
@Generated("jsonschema2pojo") @JsonIgnoreProperties(ignoreUnknown = true)
public class User { public class User {
/**
* {@link User} Avatar
*/
@JsonProperty("avatar")
@JsonPropertyDescription("User Avatar")
private String avatar;
/** /**
* {@link User} ID * {@link User} ID
*/ */
@JsonProperty("id") @JsonProperty("id")
@JsonPropertyDescription("User ID")
private Integer id; private Integer id;
/** /**
@ -97,11 +101,19 @@ public class User {
private Integer waifusTrashed; private Integer waifusTrashed;
/** /**
* <p>User's {@link TrueLove}</p> * <p>{@link User}'s {@link TrueLove}</p>
*
*/ */
@JsonProperty("true_love") @JsonProperty("true_love")
@JsonPropertyDescription("User's True Love")
private TrueLove trueLove; private TrueLove trueLove;
@JsonProperty("avatar")
public String getAvatar() { return avatar; }
@JsonProperty("avatar")
public void setAvatar(String avatar) { this.avatar = avatar; }
@JsonProperty("id") @JsonProperty("id")
public Integer getId() { public Integer getId() {
return id; return id;
@ -187,18 +199,19 @@ public class User {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
User user = (User) o; User user = (User) o;
return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(twitter, user.twitter) && Objects.equals(joined, user.joined) && Objects.equals(waifusCreated, user.waifusCreated) && Objects.equals(waifusLiked, user.waifusLiked) && Objects.equals(waifusTrashed, user.waifusTrashed) && Objects.equals(trueLove, user.trueLove); return Objects.equals(avatar, user.avatar) && Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(twitter, user.twitter) && Objects.equals(joined, user.joined) && Objects.equals(waifusCreated, user.waifusCreated) && Objects.equals(waifusLiked, user.waifusLiked) && Objects.equals(waifusTrashed, user.waifusTrashed) && Objects.equals(trueLove, user.trueLove);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, name, twitter, joined, waifusCreated, waifusLiked, waifusTrashed, trueLove); return Objects.hash(avatar, id, name, twitter, joined, waifusCreated, waifusLiked, waifusTrashed, trueLove);
} }
@Override @Override
public String toString() { public String toString() {
return "User{" + return "User{" +
"id=" + id + "avatar='" + avatar + '\'' +
", id=" + id +
", name='" + name + '\'' + ", name='" + name + '\'' +
", twitter='" + twitter + '\'' + ", twitter='" + twitter + '\'' +
", joined='" + joined + '\'' + ", joined='" + joined + '\'' +

@ -1,24 +1,20 @@
package org.goudham.me.api.entity.user; package me.goudham.domain.user;
import com.fasterxml.jackson.annotation.*;
import me.goudham.domain.waifu.Waifu;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.goudham.me.api.entity.waifu.Waifu;
/** /**
* {@link UserList} * {@link UserList}
* <p>Get an array of all user lists on their profile</p> * <p>Get an array of all Waifu lists on their profile</p>
* *
* <p> Fields included are: </p> * <p> Fields included are: </p>
* <ul> * <ul>
* <li>{@link Integer id}</li> * <li>{@link Integer id}</li>
* <li>{@link String name}</li> * <li>{@link String name}</li>
* <li>{@link String order}</li> * <li>{@link Integer order}</li>
* <li>{@link List} of {@link Waifu}'s</li> * <li>{@link List} of {@link Waifu}'s</li>
* </ul> * </ul>
* *
@ -30,7 +26,7 @@ import org.goudham.me.api.entity.waifu.Waifu;
"order", "order",
"waifus" "waifus"
}) })
@Generated("jsonschema2pojo") @JsonIgnoreProperties(ignoreUnknown = true)
public class UserList { public class UserList {
/** /**
* {@link UserList} ID * {@link UserList} ID

@ -1,15 +1,10 @@
package org.goudham.me.api.entity.waifu; package me.goudham.domain.waifu;
import org.goudham.me.api.entity.series.FilteredSeries; import com.fasterxml.jackson.annotation.*;
import me.goudham.domain.series.FilteredSeries;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/** /**
@ -22,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
* <li>{@link String name}</li> * <li>{@link String name}</li>
* <li>{@link String originalName}</li> * <li>{@link String originalName}</li>
* <li>{@link Integer relevance}</li> * <li>{@link Integer relevance}</li>
* <li>{@link String romaji}</li>
* <li>{@link String romajiName}</li> * <li>{@link String romajiName}</li>
* <li>{@link String displayPicture}</li> * <li>{@link String displayPicture}</li>
* <li>{@link Integer likes}</li> * <li>{@link Integer likes}</li>
@ -39,6 +35,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
"name", "name",
"original_name", "original_name",
"relevance", "relevance",
"romaji",
"romaji_name", "romaji_name",
"display_picture", "display_picture",
"description", "description",
@ -49,7 +46,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
"appearances", "appearances",
"id" "id"
}) })
@Generated("jsonschema2pojo") @JsonIgnoreProperties(ignoreUnknown = true)
public class FilteredWaifu { public class FilteredWaifu {
/** /**
* Used to generate readable URL's for the {@link FilteredWaifu} * Used to generate readable URL's for the {@link FilteredWaifu}
@ -82,6 +79,14 @@ public class FilteredWaifu {
@JsonPropertyDescription("Relevancy of FilteredWaifu") @JsonPropertyDescription("Relevancy of FilteredWaifu")
private Integer relevance; private Integer relevance;
/**
* If this character has a romaji name, we'll put it here.
*
*/
@JsonProperty("romaji")
@JsonPropertyDescription("if this character has a romaji name, we'll put it here. ")
private String romaji;
/** /**
* If this character has a romaji name, we'll put it here. * If this character has a romaji name, we'll put it here.
* *
@ -186,6 +191,12 @@ public class FilteredWaifu {
@JsonProperty("relevance") @JsonProperty("relevance")
public void setRelevance(Integer relevance) { this.relevance = relevance; } public void setRelevance(Integer relevance) { this.relevance = relevance; }
@JsonProperty("romaji")
public String getRomaji() { return romaji; }
@JsonProperty("romaji")
public void setRomaji(String romaji) { this.romaji = romaji; }
@JsonProperty("romaji_name") @JsonProperty("romaji_name")
public String getRomajiName() { public String getRomajiName() {
return romajiName; return romajiName;
@ -275,12 +286,12 @@ public class FilteredWaifu {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
FilteredWaifu that = (FilteredWaifu) o; FilteredWaifu that = (FilteredWaifu) o;
return Objects.equals(slug, that.slug) && Objects.equals(name, that.name) && Objects.equals(originalName, that.originalName) && Objects.equals(romajiName, that.romajiName) && Objects.equals(displayPicture, that.displayPicture) && Objects.equals(description, that.description) && Objects.equals(likes, that.likes) && Objects.equals(trash, that.trash) && Objects.equals(url, that.url) && Objects.equals(appearances, that.appearances) && Objects.equals(id, that.id); return Objects.equals(slug, that.slug) && Objects.equals(name, that.name) && Objects.equals(originalName, that.originalName) && Objects.equals(relevance, that.relevance) && Objects.equals(romaji, that.romaji) && Objects.equals(romajiName, that.romajiName) && Objects.equals(displayPicture, that.displayPicture) && Objects.equals(description, that.description) && Objects.equals(likes, that.likes) && Objects.equals(trash, that.trash) && Objects.equals(type, that.type) && Objects.equals(url, that.url) && Objects.equals(appearances, that.appearances) && Objects.equals(id, that.id);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(slug, name, originalName, romajiName, displayPicture, description, likes, trash, url, appearances, id); return Objects.hash(slug, name, originalName, relevance, romaji, romajiName, displayPicture, description, likes, trash, type, url, appearances, id);
} }
@Override @Override
@ -289,11 +300,14 @@ public class FilteredWaifu {
"slug='" + slug + '\'' + "slug='" + slug + '\'' +
", name='" + name + '\'' + ", name='" + name + '\'' +
", originalName='" + originalName + '\'' + ", originalName='" + originalName + '\'' +
", relevance=" + relevance +
", romaji='" + romaji + '\'' +
", romajiName='" + romajiName + '\'' + ", romajiName='" + romajiName + '\'' +
", displayPicture='" + displayPicture + '\'' + ", displayPicture='" + displayPicture + '\'' +
", description='" + description + '\'' + ", description='" + description + '\'' +
", likes=" + likes + ", likes=" + likes +
", trash=" + trash + ", trash=" + trash +
", type='" + type + '\'' +
", url='" + url + '\'' + ", url='" + url + '\'' +
", appearances=" + appearances + ", appearances=" + appearances +
", id=" + id + ", id=" + id +

@ -1,14 +1,14 @@
package org.goudham.me.api.entity.waifu; package me.goudham.domain.waifu;
import com.fasterxml.jackson.annotation.*;
import me.goudham.domain.series.Series;
import me.goudham.domain.user.Creator;
import javax.annotation.processing.Generated;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.*;
import org.goudham.me.api.entity.series.Series;
import org.goudham.me.api.entity.user.Creator;
/** /**
@ -81,7 +81,6 @@ import org.goudham.me.api.entity.user.Creator;
"appearances", "appearances",
"series" "series"
}) })
@Generated("jsonschema2pojo")
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class Waifu { public class Waifu {
/** /**
@ -612,12 +611,12 @@ public class Waifu {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Waifu waifu = (Waifu) o; Waifu waifu = (Waifu) o;
return Objects.equals(id, waifu.id) && Objects.equals(slug, waifu.slug) && Objects.equals(creator, waifu.creator) && Objects.equals(name, waifu.name) && Objects.equals(originalName, waifu.originalName) && Objects.equals(displayPicture, waifu.displayPicture) && Objects.equals(description, waifu.description) && Objects.equals(weight, waifu.weight) && Objects.equals(height, waifu.height) && Objects.equals(bust, waifu.bust) && Objects.equals(hip, waifu.hip) && Objects.equals(waist, waifu.waist) && bloodType == waifu.bloodType && Objects.equals(origin, waifu.origin) && Objects.equals(age, waifu.age) && Objects.equals(birthdayMonth, waifu.birthdayMonth) && Objects.equals(birthdayDay, waifu.birthdayDay) && Objects.equals(birthdayYear, waifu.birthdayYear) && Objects.equals(likes, waifu.likes) && Objects.equals(trash, waifu.trash) && Objects.equals(url, waifu.url) && Objects.equals(husbando, waifu.husbando) && Objects.equals(nsfw, waifu.nsfw) && Objects.equals(popularityRank, waifu.popularityRank) && Objects.equals(likeRank, waifu.likeRank) && Objects.equals(trashRank, waifu.trashRank) && Objects.equals(appearances, waifu.appearances) && Objects.equals(series, waifu.series); return Objects.equals(id, waifu.id) && Objects.equals(slug, waifu.slug) && Objects.equals(creator, waifu.creator) && Objects.equals(name, waifu.name) && Objects.equals(originalName, waifu.originalName) && Objects.equals(romajiName, waifu.romajiName) && Objects.equals(displayPicture, waifu.displayPicture) && Objects.equals(description, waifu.description) && Objects.equals(weight, waifu.weight) && Objects.equals(height, waifu.height) && Objects.equals(bust, waifu.bust) && Objects.equals(hip, waifu.hip) && Objects.equals(waist, waifu.waist) && bloodType == waifu.bloodType && Objects.equals(origin, waifu.origin) && Objects.equals(age, waifu.age) && Objects.equals(birthdayMonth, waifu.birthdayMonth) && Objects.equals(birthdayDay, waifu.birthdayDay) && Objects.equals(birthdayYear, waifu.birthdayYear) && Objects.equals(likes, waifu.likes) && Objects.equals(trash, waifu.trash) && Objects.equals(url, waifu.url) && Objects.equals(husbando, waifu.husbando) && Objects.equals(nsfw, waifu.nsfw) && Objects.equals(popularityRank, waifu.popularityRank) && Objects.equals(likeRank, waifu.likeRank) && Objects.equals(trashRank, waifu.trashRank) && Objects.equals(appearances, waifu.appearances) && Objects.equals(series, waifu.series);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, slug, creator, name, originalName, displayPicture, description, weight, height, bust, hip, waist, bloodType, origin, age, birthdayMonth, birthdayDay, birthdayYear, likes, trash, url, husbando, nsfw, popularityRank, likeRank, trashRank, appearances, series); return Objects.hash(id, slug, creator, name, originalName, romajiName, displayPicture, description, weight, height, bust, hip, waist, bloodType, origin, age, birthdayMonth, birthdayDay, birthdayYear, likes, trash, url, husbando, nsfw, popularityRank, likeRank, trashRank, appearances, series);
} }
@Override @Override
@ -625,9 +624,10 @@ public class Waifu {
return "Waifu{" + return "Waifu{" +
"id=" + id + "id=" + id +
", slug='" + slug + '\'' + ", slug='" + slug + '\'' +
", creatorId=" + creator + ", creator=" + creator +
", name='" + name + '\'' + ", name='" + name + '\'' +
", originalName='" + originalName + '\'' + ", originalName='" + originalName + '\'' +
", romajiName='" + romajiName + '\'' +
", displayPicture='" + displayPicture + '\'' + ", displayPicture='" + displayPicture + '\'' +
", description='" + description + '\'' + ", description='" + description + '\'' +
", weight=" + weight + ", weight=" + weight +

@ -1,11 +1,10 @@
package org.goudham.me.api.entity.waifu; package me.goudham.domain.waifu;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription; import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import javax.annotation.processing.Generated;
import java.util.Objects; import java.util.Objects;
/** /**
@ -16,7 +15,8 @@ import java.util.Objects;
* <ul> * <ul>
* <li>{@link Integer id}</li> * <li>{@link Integer id}</li>
* <li>{@link String thumbnail}</li> * <li>{@link String thumbnail}</li>
* <li>{@link String path}</li> * <li>{@link String image}</li>
* <li>{@link Boolean nsfw}</li>
* </ul> * </ul>
* *
*/ */
@ -24,9 +24,9 @@ import java.util.Objects;
@JsonPropertyOrder({ @JsonPropertyOrder({
"id", "id",
"thumbnail", "thumbnail",
"path" "image",
"nsfw"
}) })
@Generated("jsonschema2pojo")
public class WaifuImage { public class WaifuImage {
/** /**
@ -49,9 +49,17 @@ public class WaifuImage {
* Final URL of the original resolution image * Final URL of the original resolution image
* *
*/ */
@JsonProperty("path") @JsonProperty("image")
@JsonPropertyDescription("Final URL of the original resolution image") @JsonPropertyDescription("Final URL of the original resolution image")
private String path; private String image;
/**
* If image is NSFW or not
*
*/
@JsonProperty("nsfw")
@JsonPropertyDescription("If image is NSFW or not")
private String nsfw;
@JsonProperty("id") @JsonProperty("id")
public Integer getId() { public Integer getId() {
@ -73,27 +81,33 @@ public class WaifuImage {
this.thumbnail = thumbnail; this.thumbnail = thumbnail;
} }
@JsonProperty("path") @JsonProperty("image")
public String getPath() { public String getImage() {
return path; return image;
} }
@JsonProperty("path") @JsonProperty("image")
public void setPath(String path) { public void setImage(String image) {
this.path = path; this.image = image;
} }
@JsonProperty("nsfw")
public String getNsfw() { return nsfw; }
@JsonProperty("nsfw")
public void setNsfw(String nsfw) { this.nsfw = nsfw; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
WaifuImage that = (WaifuImage) o; WaifuImage that = (WaifuImage) o;
return Objects.equals(id, that.id) && Objects.equals(thumbnail, that.thumbnail) && Objects.equals(path, that.path); return Objects.equals(id, that.id) && Objects.equals(thumbnail, that.thumbnail) && Objects.equals(image, that.image) && Objects.equals(nsfw, that.nsfw);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, thumbnail, path); return Objects.hash(id, thumbnail, image, nsfw);
} }
@Override @Override
@ -101,7 +115,8 @@ public class WaifuImage {
return "WaifuImage{" + return "WaifuImage{" +
"id=" + id + "id=" + id +
", thumbnail='" + thumbnail + '\'' + ", thumbnail='" + thumbnail + '\'' +
", path='" + path + '\'' + ", image='" + image + '\'' +
", nsfw='" + nsfw + '\'' +
'}'; '}';
} }
} }

@ -1,10 +1,10 @@
package org.goudham.me.exception; package me.goudham.exception;
import org.goudham.me.APIWrapper; import me.goudham.APIWrapper;
import org.goudham.me.Response; import me.goudham.Response;
/** /**
* Thrown when {@link APIWrapper} fails to deserialize json into Java POJO's ({@link Response#getEntity()}) * Thrown when {@link APIWrapper} fails to deserialize json into Java POJO's ({@link Response#getModel()})
* *
*/ */
public class APIMapperException extends Throwable { public class APIMapperException extends Throwable {

@ -1,6 +1,6 @@
package org.goudham.me.exception; package me.goudham.exception;
import org.goudham.me.APIWrapper; import me.goudham.APIWrapper;
/** /**
* Thrown when {@link APIWrapper} fails to return API information * Thrown when {@link APIWrapper} fails to return API information

@ -0,0 +1,22 @@
package me.goudham.util;
/**
* Listing all 4 {@link Season}'s
*
*/
public enum Season {
SPRING("spring"),
SUMMER("summer"),
FALL("fall"),
WINTER("winter");
private final String season;
Season(String season) {
this.season = season;
}
public String getSeason() {
return season;
}
}

@ -1,91 +0,0 @@
package org.goudham.me;
import org.goudham.me.api.entity.series.FilteredSeries;
import org.goudham.me.api.entity.series.Series;
import org.goudham.me.api.entity.waifu.Waifu;
import org.goudham.me.exception.APIMapperException;
import org.goudham.me.exception.APIResponseException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
* Returns API information to {@link MyWaifuClient}
*/
public class APIWrapper {
private final String version = "1.0";
private static final String host = "https://mywaifulist.moe/api/v1/";
private final String apiKey;
private final APIMapper apiMapper;
/**
* Instantiates an instance of {@link APIWrapper} to retrieve API Information.
* An instance of {@link APIMapper} is created to be able to {@link APIMapper#deserialize(Result, Class)} JSON to
* Java objects
*
* @param apiKey API Key to authorise API request
*
*/
APIWrapper(String apiKey) {
this.apiKey = apiKey;
apiMapper = new APIMapper();
}
/**
* Handles sending a request to the API asynchronously using {@link HttpRequest}
* and the underlying {@link HttpClient}
*
* @param httpClient The {@link HttpClient} to use for sending {@link HttpRequest}'s
* @param param The end of the endpoint appended onto the host
* @return {@link Result}
* @throws APIResponseException If the {@link CompletableFuture Response}
* cannot be decoded or the thread was interrupted while waiting to receive the data
*
*/
private Result sendRequest(HttpClient httpClient, String param) throws APIResponseException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(host + param))
.version(httpClient.version())
.timeout(Duration.ofSeconds(20))
.headers("Content-Type", "application/json", "apikey", apiKey)
.GET()
.build();
CompletableFuture<HttpResponse<String>> response = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
int responseCode;
String responseBody;
try {
responseCode = response.thenApply(HttpResponse::statusCode).get();
responseBody = response.thenApply(HttpResponse::body).get();
} catch (InterruptedException | ExecutionException exp) {
throw new APIResponseException(exp.getMessage(), exp);
}
return new Result(responseCode, responseBody);
}
Response<Waifu> getWaifu(HttpClient httpClient, String param) throws APIResponseException, APIMapperException {
Result waifuResult = sendRequest(httpClient, "waifu/" + param);
return apiMapper.deserialize(waifuResult, Waifu.class);
}
Response<Series> getSeries(HttpClient httpClient, String param) throws APIResponseException, APIMapperException {
Result seriesResult = sendRequest(httpClient, "series/" + param);
return apiMapper.deserialize(seriesResult, Series.class);
}
Response<List<FilteredSeries>> getAiringAnime(HttpClient httpClient) throws APIResponseException, APIMapperException {
Result seriesResult = sendRequest(httpClient, "airing");
return apiMapper.deserializeToList(seriesResult, FilteredSeries.class);
}
}

@ -1,146 +0,0 @@
package org.goudham.me;
import org.goudham.me.api.entity.series.FilteredSeries;
import org.goudham.me.api.entity.series.Series;
import org.goudham.me.api.entity.waifu.Waifu;
import org.goudham.me.exception.APIMapperException;
import org.goudham.me.exception.APIResponseException;
import org.jetbrains.annotations.NotNull;
import javax.net.ssl.SSLParameters;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.ProxySelector;
import java.net.http.HttpClient;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.Executor;
/**
* A MyWaifuClient, the underlying client used for making requests is {@link HttpClient}
*
*
* <p> Main entry point for retrieving information from MyWaifuList.</p>
* <p> {@link APIWrapper} is utilised to make the API requests </p>
*/
public class MyWaifuClient {
private final APIWrapper APIWrapper;
private HttpClient httpClient;
/**
* Creates an instance of {@link MyWaifuClient}
*
* <p>See <a href="https://mywaifulist.docs.stoplight.io/">MyWaifuList</a> for obtaining an API Key</p>
* @param apiKey API Key to authorise API request
*/
MyWaifuClient(@NotNull String apiKey) {
APIWrapper = new APIWrapper(apiKey);
}
/**
* Creates an instance of {@link MyWaifuClient} with default {@link HttpClient} settings
*
* @param apiKey API Key to authorise API request
* @return {@link MyWaifuClient}
*/
public static MyWaifuClient createDefault(@NotNull String apiKey) {
MyWaifuClient myWaifuClient = new MyWaifuClient(apiKey);
myWaifuClient.setHttpClient(HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build());
return myWaifuClient;
}
public Response<Waifu> getWaifu(String slug) throws APIResponseException, APIMapperException {
return APIWrapper.getWaifu(httpClient, slug);
}
public Response<Waifu> getWaifu(Integer id) throws APIResponseException, APIMapperException {
return APIWrapper.getWaifu(httpClient, String.valueOf(id));
}
public Response<Series> getSeries(Integer id) throws APIMapperException, APIResponseException {
return APIWrapper.getSeries(httpClient, String.valueOf(id));
}
public Response<List<FilteredSeries>> getAiringAnime() throws APIMapperException, APIResponseException {
return APIWrapper.getAiringAnime(httpClient);
}
/**
* Sets an instance of HttpClient
*
* @param httpClient HttpClient for executing API requests
*/
void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
/**
* Builder for MyWaifuClient
*/
public static class Builder {
private final String apiKey;
private final APIWrapper APIWrapper;
private HttpClient.Builder httpClientBuilder;
public Builder(String apiKey) {
this.apiKey = apiKey;
APIWrapper = new APIWrapper(apiKey);
}
public Builder withCookieHandler(CookieHandler cookieHandler) {
httpClientBuilder.cookieHandler(cookieHandler);
return this;
}
public Builder withConnectTimeout(Duration duration) {
httpClientBuilder.connectTimeout(duration);
return this;
}
public Builder withSslParameters(SSLParameters sslParameters) {
httpClientBuilder.sslParameters(sslParameters);
return this;
}
public Builder withExecutor(Executor executor) {
httpClientBuilder.executor(executor);
return this;
}
public Builder withFollowRedirects(HttpClient.Redirect policy) {
httpClientBuilder.followRedirects(policy);
return this;
}
public Builder withVersion(HttpClient.Version version) {
httpClientBuilder.version(version);
return this;
}
public Builder withPriority(int priority) {
httpClientBuilder.priority(priority);
return this;
}
public Builder withProxy(ProxySelector proxySelector) {
httpClientBuilder.proxy(proxySelector);
return this;
}
public Builder withAuthenticator(Authenticator authenticator) {
httpClientBuilder.authenticator(authenticator);
return this;
}
public MyWaifuClient build() {
MyWaifuClient myWaifuClient = new MyWaifuClient(apiKey);
myWaifuClient.setHttpClient(httpClientBuilder.build());
return myWaifuClient;
}
}
}

@ -1,46 +0,0 @@
package org.goudham.me;
import org.goudham.me.api.entity.series.Series;
import org.goudham.me.api.entity.waifu.Waifu;
/**
* This is returned to the User when called by methods in {@link MyWaifuClient}.
* E.g {@link MyWaifuClient#getWaifu(Integer)}
* <br>
* Given a successful response, {@link #entity} will be populated with the requested entity.
* <br>
* No matter successful or unsuccessful response, {@link #responseCode} and {@link #responseBody}
* will be populated to ensure the user has all the information for debugging or extra information within
* the {@link #responseBody}
*
* @param <T> The type of entity to be returned. E.g {@link Waifu} or {@link Series}
*
*/
public class Response<T> {
private T entity;
private final Integer responseCode;
private final String responseBody;
Response(Integer responseCode, String responseBody, T entity) {
this.responseCode = responseCode;
this.responseBody = responseBody;
this.entity = entity;
}
Response(Integer responseCode, String responseBody) {
this.responseCode = responseCode;
this.responseBody = responseBody;
}
public T getEntity() {
return entity;
}
public Integer getResponseCode() {
return responseCode;
}
public String getResponseBody() {
return responseBody;
}
}

@ -1,105 +0,0 @@
package org.goudham.me.api.entity;
import javax.annotation.processing.Generated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/**
* {@link PaginationData}
* <p>Contains standard Pagination data from the API</p>
*
* <p> Fields included are: </p>
* <ul>
* <li>{@link Integer currentPage}</li>
* <li>{@link Integer lastPage}</li>
* <li>{@link Integer perPage}</li>
* <li>{@link Integer total}</li>
* </ul>
*
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"current_page",
"last_page",
"per_page",
"total"
})
@Generated("jsonschema2pojo")
public class PaginationData {
/**
* Current requested page
*
*/
@JsonProperty("current_page")
@JsonPropertyDescription("Current requested page")
private Integer currentPage;
/**
* Last available page
*
*/
@JsonProperty("last_page")
@JsonPropertyDescription("Last available page")
private Integer lastPage;
/**
* Total number of items per page
*
*/
@JsonProperty("per_page")
@JsonPropertyDescription("Total number of items per page")
private Integer perPage;
/**
* Total number of items
*
*/
@JsonProperty("total")
@JsonPropertyDescription("Total number of items")
private Integer total;
@JsonProperty("current_page")
public Integer getCurrentPage() {
return currentPage;
}
@JsonProperty("current_page")
public void setCurrentPage(Integer currentPage) {
this.currentPage = currentPage;
}
@JsonProperty("last_page")
public Integer getLastPage() {
return lastPage;
}
@JsonProperty("last_page")
public void setLastPage(Integer lastPage) {
this.lastPage = lastPage;
}
@JsonProperty("per_page")
public Integer getPerPage() {
return perPage;
}
@JsonProperty("per_page")
public void setPerPage(Integer perPage) {
this.perPage = perPage;
}
@JsonProperty("total")
public Integer getTotal() {
return total;
}
@JsonProperty("total")
public void setTotal(Integer total) {
this.total = total;
}
}

@ -1,20 +0,0 @@
package org.goudham.me;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
Loading…
Cancel
Save