Add ability to reflectively determine asset information
Some checks failed
Build / build (push) Failing after 1m41s
Some checks failed
Build / build (push) Failing after 1m41s
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
package be.seeseepuff.pcinv.controllers;
|
||||
|
||||
import be.seeseepuff.pcinv.services.AssetService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StartupController {
|
||||
private final AssetService assetService;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
var descriptors = assetService.getAssetDescriptors();
|
||||
log.info("Asset descriptors loaded:\n{}", descriptors);
|
||||
|
||||
var assets = assetService.countAssets();
|
||||
log.info("The repository contains {} assets.", assets);
|
||||
}
|
||||
}
|
||||
34
src/main/java/be/seeseepuff/pcinv/meta/AssetDescriptors.java
Normal file
34
src/main/java/be/seeseepuff/pcinv/meta/AssetDescriptors.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package be.seeseepuff.pcinv.meta;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Holds the descriptors for all possible asset types.
|
||||
*/
|
||||
@Getter
|
||||
public class AssetDescriptors {
|
||||
/// A collection of all types of assets.
|
||||
private final Collection<AssetProperties> assets = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Loads the asset properties from a given asset type.
|
||||
*
|
||||
* @param assetType The type of the asset to load properties for.
|
||||
*/
|
||||
public void loadFrom(Class<?> assetType) {
|
||||
var property = AssetProperties.loadFrom(assetType);
|
||||
assets.add(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
var builder = new StringBuilder();
|
||||
builder.append("AssetDescriptors [\n");
|
||||
assets.forEach(assetProperties -> builder.append(assetProperties.toString(" ")).append('\n'));
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
34
src/main/java/be/seeseepuff/pcinv/meta/AssetInfo.java
Normal file
34
src/main/java/be/seeseepuff/pcinv/meta/AssetInfo.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package be.seeseepuff.pcinv.meta;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Provides metadata about an asset type itself.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface AssetInfo {
|
||||
/**
|
||||
* The displayable name of the asset type.
|
||||
*
|
||||
* @return the display name of the asset type
|
||||
*/
|
||||
String displayName() default "";
|
||||
|
||||
/**
|
||||
* The type of the asset, which can be a string or an integer.
|
||||
*
|
||||
* @return the type of the asset
|
||||
*/
|
||||
String type() default "";
|
||||
|
||||
/**
|
||||
* Indicates whether the asset type should be visible in the UI.
|
||||
*
|
||||
* @return true if the asset type is visible, false otherwise
|
||||
*/
|
||||
boolean isVisible() default true;
|
||||
}
|
||||
69
src/main/java/be/seeseepuff/pcinv/meta/AssetProperties.java
Normal file
69
src/main/java/be/seeseepuff/pcinv/meta/AssetProperties.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package be.seeseepuff.pcinv.meta;
|
||||
|
||||
import lombok.Builder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Describes the properties of an asset
|
||||
*/
|
||||
@Builder
|
||||
public class AssetProperties {
|
||||
/// The type of property, e.g.: ram, asset, etc...
|
||||
private final String type;
|
||||
|
||||
/// The displayable name of the property, e.g.: "Random Access memory"
|
||||
private final String displayName;
|
||||
|
||||
/// Whether the asset is visible in the user interface.
|
||||
private final boolean visible;
|
||||
|
||||
/// The properties of the asset, such as "brand", "model", etc.
|
||||
@lombok.Singular
|
||||
private Collection<AssetProperty> properties;
|
||||
|
||||
/**
|
||||
* Loads the asset properties from a given asset class.
|
||||
*
|
||||
* @param assetType The class of the asset to load properties for.
|
||||
* @return An AssetProperties instance containing the loaded properties.
|
||||
*/
|
||||
public static AssetProperties loadFrom(Class<?> assetType) {
|
||||
var assetInfo = assetType.getAnnotation(AssetInfo.class);
|
||||
Objects.requireNonNull(assetInfo, "Asset class must be annotated with @AssetInfo");
|
||||
return AssetProperties.builder()
|
||||
.type(assetInfo.type())
|
||||
.displayName(assetInfo.displayName())
|
||||
.visible(assetInfo.isVisible())
|
||||
.properties(Arrays.stream(assetType.getDeclaredFields())
|
||||
.map(AssetProperty::loadFrom)
|
||||
.filter(Objects::nonNull)
|
||||
.toList())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the asset properties with the specified indentation.
|
||||
*
|
||||
* @param indent The indentation to use for formatting.
|
||||
* @return A formatted string representation of the asset properties.
|
||||
*/
|
||||
public String toString(String indent) {
|
||||
var builder = new StringBuilder();
|
||||
builder.append(indent).append("AssetProperties {\n");
|
||||
builder.append(indent).append(" type='").append(type).append("',\n");
|
||||
builder.append(indent).append(" displayName='").append(displayName).append("',\n");
|
||||
if (!visible) {
|
||||
builder.append(indent).append(" hidden").append(",\n");
|
||||
}
|
||||
builder.append(indent).append(" properties=[\n");
|
||||
for (var property : properties) {
|
||||
builder.append(indent).append(" ").append(property.toString()).append("\n");
|
||||
}
|
||||
builder.append(indent).append(" ]\n");
|
||||
builder.append(indent).append('}');
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
71
src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java
Normal file
71
src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package be.seeseepuff.pcinv.meta;
|
||||
|
||||
import be.seeseepuff.pcinv.models.AssetCondition;
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.Builder;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Represents a property of an asset, such as its name or type.
|
||||
* This class is used to define the metadata for assets in the system.
|
||||
*/
|
||||
@Builder
|
||||
public class AssetProperty {
|
||||
/// The name of the property, e.g., "brand", "model", etc.
|
||||
private final String name;
|
||||
/// The name of the property as it should be displayed, e.g., "Brand", "Model", etc.
|
||||
private final String displayName;
|
||||
/// The type of the property, which can be a string or an integer.
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* Enum representing the possible types of asset properties.
|
||||
*/
|
||||
public enum Type {
|
||||
STRING, INTEGER, CONDITION
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an AssetProperty from a given field.
|
||||
*
|
||||
* @param property The field representing the property.
|
||||
* @return An AssetProperty instance with the name, display name, and type determined from the field.
|
||||
*/
|
||||
@Nullable
|
||||
public static AssetProperty loadFrom(Field property) {
|
||||
var annotation = property.getAnnotation(Property.class);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
return AssetProperty.builder()
|
||||
.name(property.getName())
|
||||
.displayName(annotation.value())
|
||||
.type(determineType(property))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the type of the property based on its field type.
|
||||
*
|
||||
* @param property The field representing the property.
|
||||
* @return The type of the property.
|
||||
* @throws IllegalArgumentException if the property type is unsupported.
|
||||
*/
|
||||
private static Type determineType(Field property) {
|
||||
if (property.getType() == String.class) {
|
||||
return Type.STRING;
|
||||
} else if (property.getType() == Integer.class || property.getType() == int.class || property.getType() == Long.class || property.getType() == long.class) {
|
||||
return Type.INTEGER;
|
||||
} else if (property.getType() == AssetCondition.class) {
|
||||
return Type.CONDITION;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported property type: " + property.getType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s:%s (%s)", name, type.name(), displayName);
|
||||
}
|
||||
}
|
||||
20
src/main/java/be/seeseepuff/pcinv/meta/Property.java
Normal file
20
src/main/java/be/seeseepuff/pcinv/meta/Property.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package be.seeseepuff.pcinv.meta;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation to mark a property descriptor of an asset.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Property {
|
||||
/**
|
||||
* The displayable name of the property.
|
||||
*
|
||||
* @return the display name of the property
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,37 +1,7 @@
|
||||
package be.seeseepuff.pcinv.models;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
public interface Asset {
|
||||
long getId();
|
||||
|
||||
/**
|
||||
* Represents a generic asset in the inventory system.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
public class Asset
|
||||
{
|
||||
@Id @GeneratedValue
|
||||
private Long id;
|
||||
|
||||
/// The QR code attached to the asset, used for identification.
|
||||
private Long qr;
|
||||
|
||||
/// The brand of the asset.
|
||||
private String brand;
|
||||
|
||||
/// The model of the asset
|
||||
private String model;
|
||||
|
||||
/// The asset's serial number.
|
||||
private String serialNumber;
|
||||
|
||||
/// A description of the asset, providing additional details.
|
||||
private String description;
|
||||
|
||||
/// The state of the asset, indicating its condition.
|
||||
private AssetCondition condition;
|
||||
GenericAsset getAsset();
|
||||
}
|
||||
|
||||
52
src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java
Normal file
52
src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package be.seeseepuff.pcinv.models;
|
||||
|
||||
import be.seeseepuff.pcinv.meta.AssetInfo;
|
||||
import be.seeseepuff.pcinv.meta.Property;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Represents a generic asset in the inventory system.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@AssetInfo(
|
||||
displayName = "Asset",
|
||||
type = "asset",
|
||||
isVisible = false
|
||||
)
|
||||
@Table(name = "assets")
|
||||
public class GenericAsset
|
||||
{
|
||||
@Id @GeneratedValue
|
||||
private long id;
|
||||
|
||||
/// The QR code attached to the asset, used for identification.
|
||||
@Property("QR")
|
||||
private long qr;
|
||||
|
||||
/// The brand of the asset.
|
||||
@Property("Brand")
|
||||
private String brand;
|
||||
|
||||
/// The model of the asset
|
||||
@Property("Model")
|
||||
private String model;
|
||||
|
||||
/// The asset's serial number.
|
||||
@Property("Serial Number")
|
||||
private String serialNumber;
|
||||
|
||||
/// A description of the asset, providing additional details.
|
||||
@Property("Description")
|
||||
private String description;
|
||||
|
||||
/// The state of the asset, indicating its condition.
|
||||
@Property("Condition")
|
||||
private AssetCondition condition;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package be.seeseepuff.pcinv.models;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import be.seeseepuff.pcinv.meta.AssetInfo;
|
||||
import be.seeseepuff.pcinv.meta.Property;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -12,21 +12,30 @@ import lombok.Setter;
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
public class HddAsset
|
||||
@AssetInfo(
|
||||
displayName = "Hard Drive",
|
||||
type = "HDD"
|
||||
)
|
||||
@Table(name = "hdd_assets")
|
||||
public class HddAsset implements Asset
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
private long id;
|
||||
|
||||
/// The ID of the associated asset, linking it to the generic Asset model.
|
||||
private Long assetId;
|
||||
/// The generic asset associated with this HDD.
|
||||
@OneToOne(orphanRemoval = true)
|
||||
private GenericAsset asset;
|
||||
|
||||
/// The capacity of the drive in bytes.
|
||||
private Long capacity;
|
||||
@Property("Capacity")
|
||||
private long capacity;
|
||||
|
||||
/// The drive's interface type, such as SATA, IDE, ISA-16, ...
|
||||
@Property("Interface Type")
|
||||
private String interfaceType;
|
||||
|
||||
/// The drive's form factor, such as 2.5", 3.5", etc.
|
||||
@Property("Form Factor")
|
||||
private String formFactor;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package be.seeseepuff.pcinv.models;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import be.seeseepuff.pcinv.meta.AssetInfo;
|
||||
import be.seeseepuff.pcinv.meta.Property;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -12,18 +12,26 @@ import lombok.Setter;
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
public class RamAsset
|
||||
@AssetInfo(
|
||||
displayName = "Random Access Memory",
|
||||
type = "RAM"
|
||||
)
|
||||
@Table(name = "ram_assets")
|
||||
public class RamAsset implements Asset
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
private long id;
|
||||
|
||||
/// The ID of the associated asset, linking it to the generic Asset model.
|
||||
private Long assetId;
|
||||
/// The generic asset associated with this RAM.
|
||||
@OneToOne(orphanRemoval = true)
|
||||
private GenericAsset asset;
|
||||
|
||||
/// The capacity of the RAM in bytes.
|
||||
private Long capacity;
|
||||
@Property("Capacity")
|
||||
private long capacity;
|
||||
|
||||
/// The type of memory. E.g.: DDR2, SDRAM, ISA-8, etc...
|
||||
@Property("Type")
|
||||
private String type;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package be.seeseepuff.pcinv.repositories;
|
||||
|
||||
import be.seeseepuff.pcinv.models.Asset;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface AssetRepository extends CrudRepository<Asset, Long> {}
|
||||
public interface AssetRepository<T extends Asset> {
|
||||
Class<T> getAssetType();
|
||||
|
||||
long count();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package be.seeseepuff.pcinv.repositories;
|
||||
|
||||
import be.seeseepuff.pcinv.models.GenericAsset;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface GenericAssetRepository extends JpaRepository<GenericAsset, Long> {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package be.seeseepuff.pcinv.repositories;
|
||||
|
||||
import be.seeseepuff.pcinv.models.HddAsset;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface HddAssetRepository extends JpaRepository<HddAsset, Long>, AssetRepository<HddAsset> {
|
||||
@Override
|
||||
default Class<HddAsset> getAssetType() {
|
||||
return HddAsset.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package be.seeseepuff.pcinv.repositories;
|
||||
|
||||
import be.seeseepuff.pcinv.models.RamAsset;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface RamAssetRepository extends JpaRepository<RamAsset, Long>, AssetRepository<RamAsset> {
|
||||
@Override
|
||||
default Class<RamAsset> getAssetType() {
|
||||
return RamAsset.class;
|
||||
}
|
||||
}
|
||||
39
src/main/java/be/seeseepuff/pcinv/services/AssetService.java
Normal file
39
src/main/java/be/seeseepuff/pcinv/services/AssetService.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package be.seeseepuff.pcinv.services;
|
||||
|
||||
import be.seeseepuff.pcinv.meta.AssetDescriptors;
|
||||
import be.seeseepuff.pcinv.models.GenericAsset;
|
||||
import be.seeseepuff.pcinv.repositories.AssetRepository;
|
||||
import be.seeseepuff.pcinv.repositories.GenericAssetRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Service for managing assets in the repository.
|
||||
* Provides methods to interact with the asset repositories.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AssetService {
|
||||
private final GenericAssetRepository assetRepository;
|
||||
private final Collection<AssetRepository<?>> repositories;
|
||||
|
||||
/**
|
||||
* Returns the count of all assets in the repository.
|
||||
*
|
||||
* @return the total number of assets
|
||||
*/
|
||||
public long countAssets() {
|
||||
return assetRepository.count();
|
||||
}
|
||||
|
||||
public AssetDescriptors getAssetDescriptors() {
|
||||
var descriptors = new AssetDescriptors();
|
||||
descriptors.loadFrom(GenericAsset.class);
|
||||
for (var repository : repositories) {
|
||||
descriptors.loadFrom(repository.getAssetType());
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,4 @@ server.port=8088
|
||||
spring.datasource.url=jdbc:postgresql://localhost:5432/pcinv
|
||||
spring.datasource.username=pcinv
|
||||
spring.datasource.password=pcinv
|
||||
a
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
|
||||
Reference in New Issue
Block a user