Fix null pointers and unsafe parsing bugs

This commit is contained in:
2026-03-08 10:05:09 -06:00
parent aa011205a0
commit 59de8ae1aa
21 changed files with 328 additions and 80 deletions

View File

@@ -44,6 +44,28 @@ public class ApiClient {
return handleResponse(response, responseClass); return handleResponse(response, responseClass);
} }
public String getRawResponse(String path) throws Exception {
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + path))
.GET()
.timeout(Duration.ofSeconds(30));
addAuthHeader(builder);
HttpRequest request = builder.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200 || response.statusCode() == 201) {
return response.body();
} else if (response.statusCode() == 401) {
throw new RuntimeException("Authentication failed. Please log in again.");
} else if (response.statusCode() == 403) {
throw new RuntimeException("Access restricted. You don't have permission to perform this action.");
} else {
throw new RuntimeException(parseErrorMessage(response));
}
}
public <T> T post(String path, Object requestBody, Class<T> responseClass) throws Exception { public <T> T post(String path, Object requestBody, Class<T> responseClass) throws Exception {
String jsonBody = objectMapper.writeValueAsString(requestBody); String jsonBody = objectMapper.writeValueAsString(requestBody);
@@ -155,6 +177,7 @@ public class ApiClient {
} }
} }
} catch (Exception e) { } catch (Exception e) {
System.err.println("Error parsing error message: " + e.getMessage());
} }
return "Request failed with status " + response.statusCode(); return "Request failed with status " + response.statusCode();
} }

View File

@@ -5,7 +5,10 @@ import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest; import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
import org.example.petshopdesktop.api.dto.adoption.AdoptionResponse; import org.example.petshopdesktop.api.dto.adoption.AdoptionResponse;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class AdoptionApi { public class AdoptionApi {
@@ -23,10 +26,17 @@ public class AdoptionApi {
public List<AdoptionResponse> listAdoptions(String query) throws Exception { public List<AdoptionResponse> listAdoptions(String query) throws Exception {
String path = "/api/v1/adoptions?page=0&size=1000"; String path = "/api/v1/adoptions?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<AdoptionResponse>>() {}); PageResponse<AdoptionResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<AdoptionResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from adoptions endpoint");
}
return pageResponse.getContent();
} }
public AdoptionResponse createAdoption(AdoptionRequest request) throws Exception { public AdoptionResponse createAdoption(AdoptionRequest request) throws Exception {

View File

@@ -5,7 +5,10 @@ import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest; import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest;
import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse; import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class AppointmentApi { public class AppointmentApi {
@@ -23,10 +26,17 @@ public class AppointmentApi {
public List<AppointmentResponse> listAppointments(String query) throws Exception { public List<AppointmentResponse> listAppointments(String query) throws Exception {
String path = "/api/v1/appointments?page=0&size=1000"; String path = "/api/v1/appointments?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<AppointmentResponse>>() {}); PageResponse<AppointmentResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<AppointmentResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from appointments endpoint");
}
return pageResponse.getContent();
} }
public AppointmentResponse createAppointment(AppointmentRequest request) throws Exception { public AppointmentResponse createAppointment(AppointmentRequest request) throws Exception {

View File

@@ -19,37 +19,58 @@ public class DropdownApi {
} }
public List<DropdownOption> getCategories() throws Exception { public List<DropdownOption> getCategories() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/categories", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/categories");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from categories endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
public List<DropdownOption> getProducts() throws Exception { public List<DropdownOption> getProducts() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/products", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/products");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from products endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
public List<DropdownOption> getSuppliers() throws Exception { public List<DropdownOption> getSuppliers() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/suppliers", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/suppliers");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from suppliers endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
public List<DropdownOption> getServices() throws Exception { public List<DropdownOption> getServices() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/services", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/services");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from services endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
public List<DropdownOption> getCustomers() throws Exception { public List<DropdownOption> getCustomers() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/customers", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/customers");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from customers endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
public List<DropdownOption> getPets() throws Exception { public List<DropdownOption> getPets() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/pets", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/pets");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from pets endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
public List<DropdownOption> getStores() throws Exception { public List<DropdownOption> getStores() throws Exception {
String response = apiClient.get("/api/v1/dropdowns/stores", String.class); String response = apiClient.getRawResponse("/api/v1/dropdowns/stores");
if (response == null || response.isEmpty()) {
throw new IllegalStateException("Empty response from stores endpoint");
}
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {}); return apiClient.getObjectMapper().readValue(response, new TypeReference<List<DropdownOption>>() {});
} }
} }

View File

@@ -2,9 +2,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.inventory.InventoryRequest; import org.example.petshopdesktop.api.dto.inventory.InventoryRequest;
import org.example.petshopdesktop.api.dto.inventory.InventoryResponse; import org.example.petshopdesktop.api.dto.inventory.InventoryResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class InventoryApi { public class InventoryApi {
@@ -22,10 +25,17 @@ public class InventoryApi {
public List<InventoryResponse> listInventory(String query) throws Exception { public List<InventoryResponse> listInventory(String query) throws Exception {
String path = "/api/v1/inventory?page=0&size=1000"; String path = "/api/v1/inventory?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<InventoryResponse>>() {}); PageResponse<InventoryResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<InventoryResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from inventory endpoint");
}
return pageResponse.getContent();
} }
public InventoryResponse createInventory(InventoryRequest request) throws Exception { public InventoryResponse createInventory(InventoryRequest request) throws Exception {

View File

@@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.pet.PetRequest; import org.example.petshopdesktop.api.dto.pet.PetRequest;
import org.example.petshopdesktop.api.dto.pet.PetResponse; import org.example.petshopdesktop.api.dto.pet.PetResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class PetApi { public class PetApi {
@@ -23,10 +26,17 @@ public class PetApi {
public List<PetResponse> listPets(String query) throws Exception { public List<PetResponse> listPets(String query) throws Exception {
String path = "/api/v1/pets?page=0&size=1000"; String path = "/api/v1/pets?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<PetResponse>>() {}); PageResponse<PetResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<PetResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from pets endpoint");
}
return pageResponse.getContent();
} }
public PetResponse createPet(PetRequest request) throws Exception { public PetResponse createPet(PetRequest request) throws Exception {

View File

@@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.product.ProductRequest; import org.example.petshopdesktop.api.dto.product.ProductRequest;
import org.example.petshopdesktop.api.dto.product.ProductResponse; import org.example.petshopdesktop.api.dto.product.ProductResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class ProductApi { public class ProductApi {
@@ -23,10 +26,17 @@ public class ProductApi {
public List<ProductResponse> listProducts(String query) throws Exception { public List<ProductResponse> listProducts(String query) throws Exception {
String path = "/api/v1/products?page=0&size=1000"; String path = "/api/v1/products?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<ProductResponse>>() {}); PageResponse<ProductResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<ProductResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from products endpoint");
}
return pageResponse.getContent();
} }
public ProductResponse createProduct(ProductRequest request) throws Exception { public ProductResponse createProduct(ProductRequest request) throws Exception {

View File

@@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest; import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest;
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse; import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class ProductSupplierApi { public class ProductSupplierApi {
@@ -23,10 +26,17 @@ public class ProductSupplierApi {
public List<ProductSupplierResponse> listProductSuppliers(String query) throws Exception { public List<ProductSupplierResponse> listProductSuppliers(String query) throws Exception {
String path = "/api/v1/product-suppliers?page=0&size=1000"; String path = "/api/v1/product-suppliers?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<ProductSupplierResponse>>() {}); PageResponse<ProductSupplierResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<ProductSupplierResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from product-suppliers endpoint");
}
return pageResponse.getContent();
} }
public ProductSupplierResponse createProductSupplier(ProductSupplierRequest request) throws Exception { public ProductSupplierResponse createProductSupplier(ProductSupplierRequest request) throws Exception {

View File

@@ -2,8 +2,11 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse; import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class PurchaseOrderApi { public class PurchaseOrderApi {
@@ -21,9 +24,16 @@ public class PurchaseOrderApi {
public List<PurchaseOrderResponse> listPurchaseOrders(String query) throws Exception { public List<PurchaseOrderResponse> listPurchaseOrders(String query) throws Exception {
String path = "/api/v1/purchase-orders?page=0&size=1000"; String path = "/api/v1/purchase-orders?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<PurchaseOrderResponse>>() {}); PageResponse<PurchaseOrderResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<PurchaseOrderResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from purchase-orders endpoint");
}
return pageResponse.getContent();
} }
} }

View File

@@ -2,9 +2,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.sale.SaleRequest; import org.example.petshopdesktop.api.dto.sale.SaleRequest;
import org.example.petshopdesktop.api.dto.sale.SaleResponse; import org.example.petshopdesktop.api.dto.sale.SaleResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class SaleApi { public class SaleApi {
@@ -22,10 +25,17 @@ public class SaleApi {
public List<SaleResponse> listSales(int page, int size, String query) throws Exception { public List<SaleResponse> listSales(int page, int size, String query) throws Exception {
String path = "/api/v1/sales?page=" + page + "&size=" + size; String path = "/api/v1/sales?page=" + page + "&size=" + size;
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<SaleResponse>>() {}); PageResponse<SaleResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<SaleResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from sales endpoint");
}
return pageResponse.getContent();
} }
public SaleResponse getSale(Long id) throws Exception { public SaleResponse getSale(Long id) throws Exception {

View File

@@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.service.ServiceRequest; import org.example.petshopdesktop.api.dto.service.ServiceRequest;
import org.example.petshopdesktop.api.dto.service.ServiceResponse; import org.example.petshopdesktop.api.dto.service.ServiceResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class ServiceApi { public class ServiceApi {
@@ -23,10 +26,17 @@ public class ServiceApi {
public List<ServiceResponse> listServices(String query) throws Exception { public List<ServiceResponse> listServices(String query) throws Exception {
String path = "/api/v1/services?page=0&size=1000"; String path = "/api/v1/services?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<ServiceResponse>>() {}); PageResponse<ServiceResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<ServiceResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from services endpoint");
}
return pageResponse.getContent();
} }
public ServiceResponse createService(ServiceRequest request) throws Exception { public ServiceResponse createService(ServiceRequest request) throws Exception {

View File

@@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.supplier.SupplierRequest; import org.example.petshopdesktop.api.dto.supplier.SupplierRequest;
import org.example.petshopdesktop.api.dto.supplier.SupplierResponse; import org.example.petshopdesktop.api.dto.supplier.SupplierResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class SupplierApi { public class SupplierApi {
@@ -23,10 +26,17 @@ public class SupplierApi {
public List<SupplierResponse> listSuppliers(String query) throws Exception { public List<SupplierResponse> listSuppliers(String query) throws Exception {
String path = "/api/v1/suppliers?page=0&size=1000"; String path = "/api/v1/suppliers?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<SupplierResponse>>() {}); PageResponse<SupplierResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<SupplierResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from suppliers endpoint");
}
return pageResponse.getContent();
} }
public SupplierResponse createSupplier(SupplierRequest request) throws Exception { public SupplierResponse createSupplier(SupplierRequest request) throws Exception {

View File

@@ -2,9 +2,12 @@ package org.example.petshopdesktop.api.endpoints;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.ApiClient;
import org.example.petshopdesktop.api.dto.common.PageResponse;
import org.example.petshopdesktop.api.dto.user.UserRequest; import org.example.petshopdesktop.api.dto.user.UserRequest;
import org.example.petshopdesktop.api.dto.user.UserResponse; import org.example.petshopdesktop.api.dto.user.UserResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class UserApi { public class UserApi {
@@ -22,10 +25,17 @@ public class UserApi {
public List<UserResponse> listUsers(String query) throws Exception { public List<UserResponse> listUsers(String query) throws Exception {
String path = "/api/v1/users?page=0&size=1000"; String path = "/api/v1/users?page=0&size=1000";
if (query != null && !query.isEmpty()) { if (query != null && !query.isEmpty()) {
path += "&q=" + query; path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
} }
String response = apiClient.get(path, String.class); String response = apiClient.getRawResponse(path);
return apiClient.getObjectMapper().readValue(response, new TypeReference<List<UserResponse>>() {}); PageResponse<UserResponse> pageResponse = apiClient.getObjectMapper().readValue(
response,
new TypeReference<PageResponse<UserResponse>>() {}
);
if (pageResponse == null) {
throw new IllegalStateException("Null response from users endpoint");
}
return pageResponse.getContent();
} }
public UserResponse createUser(UserRequest request) throws Exception { public UserResponse createUser(UserRequest request) throws Exception {

View File

@@ -54,17 +54,27 @@ public class LoginController {
LoginRequest loginRequest = new LoginRequest(username, password); LoginRequest loginRequest = new LoginRequest(username, password);
LoginResponse loginResponse = apiClient.post("/api/v1/auth/login", loginRequest, LoginResponse.class); LoginResponse loginResponse = apiClient.post("/api/v1/auth/login", loginRequest, LoginResponse.class);
if (loginResponse == null) {
throw new IllegalStateException("Login response is null");
}
String token = loginResponse.getToken(); String token = loginResponse.getToken();
String roleStr = loginResponse.getRole(); String roleStr = loginResponse.getRole();
if (token == null || roleStr == null) {
throw new IllegalStateException("Token or role is null");
}
Role role = Role.valueOf(roleStr.toUpperCase()); Role role = Role.valueOf(roleStr.toUpperCase());
UserSession.getInstance().login(null, username, role, token); UserSession.getInstance().login(null, username, role, token);
UserInfoResponse userInfo = apiClient.get("/api/v1/auth/me", UserInfoResponse.class); UserInfoResponse userInfo = apiClient.get("/api/v1/auth/me", UserInfoResponse.class);
if (userInfo == null) {
throw new IllegalStateException("User info is null");
}
UserSession.getInstance().login(userInfo.getId(), username, role, token); UserSession.getInstance().login(userInfo.getId(), username, role, token);
List<DropdownOption> stores = DropdownApi.getInstance().getStores(); List<DropdownOption> stores = DropdownApi.getInstance().getStores();
if (!stores.isEmpty()) { if (stores != null && !stores.isEmpty()) {
UserSession.getInstance().setStoreId(stores.get(0).getId()); UserSession.getInstance().setStoreId(stores.get(0).getId());
} }

View File

@@ -67,8 +67,10 @@ public class AdoptionDialogController {
try { try {
List<DropdownOption> pets = DropdownApi.getInstance().getPets(); List<DropdownOption> pets = DropdownApi.getInstance().getPets();
Platform.runLater(() -> { Platform.runLater(() -> {
if (pets != null) {
ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets); ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
cbPet.setItems(petsObs); cbPet.setItems(petsObs);
}
}); });
} catch (Exception e) { } catch (Exception e) {
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -85,8 +87,10 @@ public class AdoptionDialogController {
try { try {
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers(); List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
Platform.runLater(() -> { Platform.runLater(() -> {
if (customers != null) {
ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers); ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers);
cbCustomer.setItems(customersObs); cbCustomer.setItems(customersObs);
}
}); });
} catch (Exception e) { } catch (Exception e) {
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -144,7 +148,11 @@ public class AdoptionDialogController {
if (mode.equals("Add")) { if (mode.equals("Add")) {
AdoptionApi.getInstance().createAdoption(request); AdoptionApi.getInstance().createAdoption(request);
} else { } else {
Long adoptionId = Long.parseLong(lblAdoptionId.getText().split(": ")[1]); String[] parts = lblAdoptionId.getText().split(": ");
if (parts.length < 2) {
throw new IllegalStateException("Invalid adoption ID format");
}
Long adoptionId = Long.parseLong(parts[1]);
AdoptionApi.getInstance().updateAdoption(adoptionId, request); AdoptionApi.getInstance().updateAdoption(adoptionId, request);
} }
@@ -197,7 +205,14 @@ public class AdoptionDialogController {
} }
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) { if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
try {
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate())); dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
} catch (Exception e) {
ActivityLogger.getInstance().logException(
"AdoptionDialogController.displayAdoptionDetails",
e,
"Parsing adoption date");
}
} }
for (String status : cbAdoptionStatus.getItems()) { for (String status : cbAdoptionStatus.getItems()) {

View File

@@ -80,9 +80,15 @@ public class AppointmentDialogController {
List<DropdownOption> pets = DropdownApi.getInstance().getPets(); List<DropdownOption> pets = DropdownApi.getInstance().getPets();
Platform.runLater(() -> { Platform.runLater(() -> {
if (services != null) {
cbService.setItems(FXCollections.observableArrayList(services)); cbService.setItems(FXCollections.observableArrayList(services));
}
if (customers != null) {
cbCustomer.setItems(FXCollections.observableArrayList(customers)); cbCustomer.setItems(FXCollections.observableArrayList(customers));
}
if (pets != null) {
cbPet.setItems(FXCollections.observableArrayList(pets)); cbPet.setItems(FXCollections.observableArrayList(pets));
}
}); });
} catch (Exception e) { } catch (Exception e) {
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -163,15 +169,29 @@ public class AppointmentDialogController {
selectedAppointment = appt; selectedAppointment = appt;
lblAppointmentId.setText("ID: " + appt.getAppointmentId()); lblAppointmentId.setText("ID: " + appt.getAppointmentId());
try {
dpAppointmentDate.setValue( dpAppointmentDate.setValue(
java.time.LocalDate.parse(appt.getAppointmentDate()) java.time.LocalDate.parse(appt.getAppointmentDate())
); );
} catch (Exception e) {
ActivityLogger.getInstance().logException(
"AppointmentDialogController.displayAppointmentDetails",
e,
"Parsing appointment date");
}
cbAppointmentStatus.setValue(appt.getAppointmentStatus()); cbAppointmentStatus.setValue(appt.getAppointmentStatus());
try {
LocalTime time = LocalTime.parse(appt.getAppointmentTime()); LocalTime time = LocalTime.parse(appt.getAppointmentTime());
cbHour.setValue(time.getHour()); cbHour.setValue(time.getHour());
cbMinute.setValue(time.getMinute()); cbMinute.setValue(time.getMinute());
} catch (Exception e) {
ActivityLogger.getInstance().logException(
"AppointmentDialogController.displayAppointmentDetails",
e,
"Parsing appointment time");
}
cbService.getItems().forEach(s -> { cbService.getItems().forEach(s -> {
if (s.getId() == appt.getServiceId()) cbService.setValue(s); if (s.getId() == appt.getServiceId()) cbService.setValue(s);

View File

@@ -70,6 +70,7 @@ public class InventoryDialogController {
//Load product list from API into combobox //Load product list from API into combobox
try { try {
List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null); List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null);
if (productResponses != null) {
ObservableList<Product> products = FXCollections.observableArrayList(); ObservableList<Product> products = FXCollections.observableArrayList();
for (ProductResponse pr : productResponses) { for (ProductResponse pr : productResponses) {
products.add(new Product( products.add(new Product(
@@ -81,6 +82,7 @@ public class InventoryDialogController {
)); ));
} }
cbProduct.setItems(products); cbProduct.setItems(products);
}
} catch (Exception e) { } catch (Exception e) {
ActivityLogger.getInstance().logException( ActivityLogger.getInstance().logException(
"InventoryDialogController.initialize", "InventoryDialogController.initialize",
@@ -126,12 +128,22 @@ public class InventoryDialogController {
InventoryRequest request = new InventoryRequest(); InventoryRequest request = new InventoryRequest();
Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
request.setProductId((long) selectedProduct.getProdId()); request.setProductId((long) selectedProduct.getProdId());
request.setStockQuantity(Integer.parseInt(txtQuantity.getText())); int quantity;
try {
quantity = Integer.parseInt(txtQuantity.getText());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid quantity format");
}
request.setStockQuantity(quantity);
if (mode.equals("Add")) { if (mode.equals("Add")) {
InventoryApi.getInstance().createInventory(request); InventoryApi.getInstance().createInventory(request);
} else { } else {
Long inventoryId = Long.parseLong(lblInventoryId.getText().split(": ")[1]); String[] parts = lblInventoryId.getText().split(": ");
if (parts.length < 2) {
throw new IllegalStateException("Invalid inventory ID format");
}
Long inventoryId = Long.parseLong(parts[1]);
InventoryApi.getInstance().updateInventory(inventoryId, request); InventoryApi.getInstance().updateInventory(inventoryId, request);
} }

View File

@@ -107,7 +107,11 @@ public class PetDialogController {
if(mode.equals("Add")) { if(mode.equals("Add")) {
PetApi.getInstance().createPet(request); PetApi.getInstance().createPet(request);
} else { } else {
Long petId = Long.parseLong(lblPetId.getText().split(": ")[1]); String[] parts = lblPetId.getText().split(": ");
if (parts.length < 2) {
throw new IllegalStateException("Invalid pet ID format");
}
Long petId = Long.parseLong(parts[1]);
PetApi.getInstance().updatePet(petId, request); PetApi.getInstance().updatePet(petId, request);
} }
@@ -142,9 +146,18 @@ public class PetDialogController {
request.setSpecies(txtPetSpecies.getText()); request.setSpecies(txtPetSpecies.getText());
request.setBreed(txtPetBreed.getText()); request.setBreed(txtPetBreed.getText());
request.setPetStatus(cbPetStatus.getValue()); request.setPetStatus(cbPetStatus.getValue());
try {
request.setPrice(new BigDecimal(txtPetPrice.getText())); request.setPrice(new BigDecimal(txtPetPrice.getText()));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid price format");
}
int age = Integer.parseInt(txtPetAge.getText()); int age;
try {
age = Integer.parseInt(txtPetAge.getText());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid age format");
}
LocalDate dateOfBirth = LocalDate.now().minusYears(age); LocalDate dateOfBirth = LocalDate.now().minusYears(age);
request.setDateOfBirth(dateOfBirth); request.setDateOfBirth(dateOfBirth);

View File

@@ -70,14 +70,16 @@ public class ProductDialogController {
//Set up combobox for selecting category //Set up combobox for selecting category
try { try {
List<DropdownOption> categories = DropdownApi.getInstance().getCategories(); List<DropdownOption> categories = DropdownApi.getInstance().getCategories();
if (categories != null) {
ObservableList<DropdownOption> categoriesObs = FXCollections.observableArrayList(categories); ObservableList<DropdownOption> categoriesObs = FXCollections.observableArrayList(categories);
cbProdCategory.setItems(categoriesObs); cbProdCategory.setItems(categoriesObs);
}
} catch (Exception e) { } catch (Exception e) {
ActivityLogger.getInstance().logException( ActivityLogger.getInstance().logException(
"ProductDialogController.initialize", "ProductDialogController.initialize",
e, e,
"Loading categories for combo box"); "Loading categories for combo box");
throw new RuntimeException(e); System.out.println("Error loading categories: " + e.getMessage());
} }
} }
@@ -110,14 +112,24 @@ public class ProductDialogController {
try { try {
ProductRequest request = new ProductRequest(); ProductRequest request = new ProductRequest();
request.setProductName(txtProdName.getText()); request.setProductName(txtProdName.getText());
request.setPrice(new BigDecimal(txtProdPrice.getText())); BigDecimal price;
try {
price = new BigDecimal(txtProdPrice.getText());
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid price format");
}
request.setPrice(price);
request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId()); request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId());
request.setDescription(txtProdDesc.getText()); request.setDescription(txtProdDesc.getText());
if (mode.equals("Add")) { if (mode.equals("Add")) {
ProductApi.getInstance().createProduct(request); ProductApi.getInstance().createProduct(request);
} else { } else {
Long productId = Long.parseLong(lblProdId.getText().split(": ")[1]); String[] parts = lblProdId.getText().split(": ");
if (parts.length < 2) {
throw new IllegalStateException("Invalid product ID format");
}
Long productId = Long.parseLong(parts[1]);
ProductApi.getInstance().updateProduct(productId, request); ProductApi.getInstance().updateProduct(productId, request);
} }

View File

@@ -119,8 +119,12 @@ public class ProductSupplierDialogController {
var products = DropdownApi.getInstance().getProducts(); var products = DropdownApi.getInstance().getProducts();
Platform.runLater(() -> { Platform.runLater(() -> {
if (suppliers != null) {
cbSupplier.setItems(FXCollections.observableArrayList(suppliers)); cbSupplier.setItems(FXCollections.observableArrayList(suppliers));
}
if (products != null) {
cbProduct.setItems(FXCollections.observableArrayList(products)); cbProduct.setItems(FXCollections.observableArrayList(products));
}
}); });
} catch (Exception e) { } catch (Exception e) {
Platform.runLater(() -> { Platform.runLater(() -> {
@@ -204,7 +208,11 @@ public class ProductSupplierDialogController {
ProductSupplierRequest request = new ProductSupplierRequest(); ProductSupplierRequest request = new ProductSupplierRequest();
request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId()); request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId());
request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId()); request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId());
try {
request.setSupplierPrice(new BigDecimal(txtCost.getText())); request.setSupplierPrice(new BigDecimal(txtCost.getText()));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid cost format");
}
return request; return request;
} }

View File

@@ -99,7 +99,11 @@ public class SupplierDialogController {
if (mode.equals("Add")) { if (mode.equals("Add")) {
SupplierApi.getInstance().createSupplier(request); SupplierApi.getInstance().createSupplier(request);
} else { } else {
Long supplierId = Long.parseLong(lblSupId.getText().split(": ")[1]); String[] parts = lblSupId.getText().split(": ");
if (parts.length < 2) {
throw new IllegalStateException("Invalid supplier ID format");
}
Long supplierId = Long.parseLong(parts[1]);
SupplierApi.getInstance().updateSupplier(supplierId, request); SupplierApi.getInstance().updateSupplier(supplierId, request);
} }