diff --git a/CLAUDE.md b/CLAUDE.md index 642ca0ff..048c11c6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -131,6 +131,27 @@ The project uses MapStruct for entity-to-DTO mappings: DTOs mirror ESPI XML schema structure and are used exclusively for XML representations. JSON is only used by openespi-authserver for OAuth2 operations. +#### JAXB Annotation Guidelines +**CRITICAL: JAXB annotations MUST only be applied to DTO classes, NEVER to entity or embeddable classes.** + +- **Entity/Embeddable Classes** (`domain/` packages): + - Use JPA annotations only: `@Entity`, `@Table`, `@Column`, `@Embeddable`, etc. + - **ABSOLUTELY NO JAXB annotations**: Do not use `@XmlType`, `@XmlAccessorType`, `@XmlElement`, `@XmlRootElement` + - Purpose: JPA persistence layer only + +- **DTO Classes** (`dto/` packages): + - Use JAXB annotations: `@XmlType`, `@XmlAccessorType`, `@XmlElement`, `@XmlRootElement` + - NO JPA annotations + - Purpose: XML marshalling/unmarshalling only + +**If an embeddable class needs XML serialization but has no DTO:** Create a corresponding DTO class rather than adding JAXB annotations to the embeddable. This rule has NO exceptions. + +**Rationale:** When both entity and DTO classes have JAXB annotations with the same XML type name and namespace, JAXB throws `IllegalAnnotationsException` due to duplicate type definitions when both are loaded in the same context. This strict separation ensures: +1. Clean architecture (persistence vs. presentation layers) +2. No JAXB namespace conflicts +3. Entities can be refactored without affecting XML schema +4. DTOs can be optimized for XML without affecting database schema + ## Database Management ### Supported Databases diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/BillingChargeSource.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/BillingChargeSource.java index 2c48c1dc..f9dc44d9 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/BillingChargeSource.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/BillingChargeSource.java @@ -30,12 +30,17 @@ /** * Embeddable value object for BillingChargeSource. - *

- * Information about the source of billing charge. - * Per ESPI 4.0 XSD (espi.xsd:1628-1643), BillingChargeSource extends Object - * and contains a single agencyName field. - *

+ * + *

Information about the source of billing charge. + * Contains a single agencyName field identifying the billing agency. * Embedded within UsageSummary entity. + * + *

Per ESPI 4.0 espi.xsd lines 1628-1643. + * + *

Note: JAXB annotations are on BillingChargeSourceDto for XML marshalling. + * This entity class is for JPA persistence only. + * + * @see ESPI Specification */ @Embeddable @Data @@ -43,22 +48,24 @@ @AllArgsConstructor public class BillingChargeSource implements Serializable { - @Serial - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Name of the billing source agency. - * Maximum length 256 characters per String256 type. - */ - @Column(name = "billing_charge_source_agency_name", length = 256) - private String agencyName; + /** + * Name of the billing source agency. + * + *

Optional field (nullable). Maximum length 256 characters per String256 type. + * XSD: espi.xsd line 1635 + */ + @Column(name = "billing_charge_source_agency_name", length = 256) + private String agencyName; - /** - * Checks if this billing charge source has a value. - * - * @return true if agency name is present - */ - public boolean hasValue() { - return agencyName != null && !agencyName.trim().isEmpty(); - } + /** + * Checks if this billing charge source has a value. + * + * @return true if agency name is present + */ + public boolean hasValue() { + return agencyName != null && !agencyName.trim().isEmpty(); + } } diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/DateTimeInterval.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/DateTimeInterval.java index 9501d8f3..c68e65ff 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/DateTimeInterval.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/DateTimeInterval.java @@ -19,24 +19,61 @@ package org.greenbuttonalliance.espi.common.domain.common; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.Setter; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; +import lombok.Setter; + import jakarta.persistence.Column; import jakarta.persistence.Embeddable; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlType; +/** + * Date and time interval with duration. + * + *

Embeddable component used for time period specifications in ESPI entities. + * Represents a time interval with start timestamp and duration in seconds. + * Both fields are required per ESPI 4.0 specification. + * + *

Per ESPI 4.0 espi.xsd lines 1337-1357. + * + * @see ESPI Specification + */ @Embeddable +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "DateTimeInterval", namespace = "http://naesb.org/espi", propOrder = { + "duration", + "start" +}) @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class DateTimeInterval { - @Column(name = "start") - private Long start; - - @Column(name = "duration") + /** + * Duration of the interval, in seconds. + * + *

Required field. Type: UInt32 (unsigned 32-bit integer, max 4,294,967,295). + * XSD: espi.xsd line 1344 + */ + @XmlElement(name = "duration", namespace = "http://naesb.org/espi", required = true) + @Column(name = "duration", nullable = false) private Long duration; + /** + * Date and time that this interval started. + * + *

Required field. Type: TimeType (seconds since Unix epoch, Jan 1, 1970 UTC). + * XSD: espi.xsd line 1349 + */ + @XmlElement(name = "start", namespace = "http://naesb.org/espi", required = true) + @Column(name = "start", nullable = false) + private Long start; + } \ No newline at end of file diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/LinkType.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/LinkType.java index c86921c5..7252067e 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/LinkType.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/LinkType.java @@ -19,29 +19,75 @@ package org.greenbuttonalliance.espi.common.domain.common; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.Setter; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; +import lombok.Setter; + import jakarta.persistence.Column; import jakarta.persistence.Embeddable; +/** + * Embeddable value object for Atom feed links. + * + *

Represents Atom link elements used in ESPI feed responses for resource relationships. + * Supports the Atom Syndication Format (RFC 4287) link element attributes. + * + *

Note: This is a custom class not directly from ESPI XSD. It supports + * the Atom namespace requirements for ESPI RESTful resource representations. + * + *

Common link relationships: + *

+ * + * @see RFC 4287 - Atom Link Element + */ @Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class LinkType { + /** + * The link's IRI (Internationalized Resource Identifier). + * + *

URI reference to the linked resource. + * RFC 4287: atom:link element's href attribute. + */ @Column(name = "href") private String href; + /** + * The link relationship type. + * + *

Describes the relationship between the current resource and the linked resource. + * Common values: "self", "up", "related", "alternate". + * RFC 4287: atom:link element's rel attribute. + */ @Column(name = "rel") private String rel; + /** + * Advisory media type hint. + * + *

MIME type of the linked resource (e.g., "application/xml", "text/html"). + * RFC 4287: atom:link element's type attribute. + */ @Column(name = "type") private String type; + /** + * Convenience constructor for links without media type. + * + * @param href the link URI + * @param rel the relationship type + */ public LinkType(String href, String rel) { this.href = href; this.rel = rel; diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/RationalNumber.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/RationalNumber.java index 858e6a64..51413625 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/RationalNumber.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/RationalNumber.java @@ -19,25 +19,62 @@ package org.greenbuttonalliance.espi.common.domain.common; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.Setter; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; -import jakarta.persistence.Column; +import lombok.Setter; + import jakarta.persistence.Embeddable; + import java.math.BigInteger; +/** + * Rational number represented as numerator / denominator. + * + *

Embeddable component used for precise fractional values in ESPI entities. + * Both numerator and denominator are optional (nullable) per ESPI 4.0 specification. + * + *

Per ESPI 4.0 espi.xsd lines 1406-1418. + * + *

Note: JAXB annotations are on RationalNumberDto for XML marshalling. + * This entity class is for JPA persistence only. + * + * @see ESPI Specification + */ @Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class RationalNumber { - @Column(name = "numerator") + /** + * Numerator of the rational number. + * + *

Optional field (nullable). Type: xs:integer from XSD. + * XSD: espi.xsd line 1413 + * + *

Note: Uses DECIMAL(38,0) column type for database compatibility while maintaining + * BigInteger type in Java for XSD compliance. Column type is specified in entity + * @AttributeOverride annotations. + */ private BigInteger numerator; - @Column(name = "denominator") + /** + * Denominator of the rational number. + * + *

Optional field (nullable). Type: assumed xs:integer from context. + * XSD: espi.xsd line 1414 + * + *

Note: XSD does not explicitly specify type for denominator. + * Implementation assumes xs:integer based on RationalNumber semantics. + * + *

Uses DECIMAL(38,0) column type for database compatibility while maintaining + * BigInteger type in Java for XSD compliance. Column type is specified in entity + * @AttributeOverride annotations. + */ private BigInteger denominator; } \ No newline at end of file diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/ReadingInterharmonic.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/ReadingInterharmonic.java index 9baef8b4..619af7c5 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/ReadingInterharmonic.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/ReadingInterharmonic.java @@ -19,24 +19,64 @@ package org.greenbuttonalliance.espi.common.domain.common; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.Setter; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; -import jakarta.persistence.Column; +import lombok.Setter; + import jakarta.persistence.Embeddable; +import java.math.BigInteger; + +/** + * Interharmonic reading represented as numerator / denominator. + * + *

Embeddable component used for harmonic and interharmonic measurements in reading types. + * Harmonics are identified by denominator = 1. Both numerator and denominator are + * optional (nullable) per ESPI 4.0 specification. + * + *

Per ESPI 4.0 espi.xsd lines 1419-1431. + * + *

Note: JAXB annotations are on ReadingInterharmonicDto for XML marshalling. + * This entity class is for JPA persistence only. + * + * @see ESPI Specification + */ @Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class ReadingInterharmonic { - @Column(name = "denominator") - private Long denominator; + /** + * Numerator of the interharmonic rational number. + * + *

Optional field (nullable). Type: xs:integer from XSD. + * XSD: espi.xsd line 1426 + * + *

Note: Uses DECIMAL(38,0) column type for database compatibility while maintaining + * BigInteger type in Java for XSD compliance. Column type is specified in entity + * @AttributeOverride annotations. + */ + private BigInteger numerator; - @Column(name = "numerator") - private Long numerator; + /** + * Denominator of the interharmonic rational number. + * Harmonics are identified by denominator = 1. + * + *

Optional field (nullable). Type: assumed xs:integer from context. + * XSD: espi.xsd line 1427 + * + *

Note: XSD does not explicitly specify type for denominator (schema bug). + * Implementation assumes xs:integer based on ReadingInterharmonic semantics. + * + *

Uses DECIMAL(38,0) column type for database compatibility while maintaining + * BigInteger type in Java for XSD compliance. Column type is specified in entity + * @AttributeOverride annotations. + */ + private BigInteger denominator; } \ No newline at end of file diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/SummaryMeasurement.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/SummaryMeasurement.java index c174b4dc..ac014b05 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/SummaryMeasurement.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/common/SummaryMeasurement.java @@ -19,26 +19,84 @@ package org.greenbuttonalliance.espi.common.domain.common; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.Setter; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; +import lombok.Setter; +import org.greenbuttonalliance.espi.common.domain.usage.enums.UnitMultiplierKind; +import org.greenbuttonalliance.espi.common.domain.usage.enums.UnitSymbolKind; + +import jakarta.persistence.Column; import jakarta.persistence.Embeddable; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +/** + * Summary measurement data embedded in usage summary entities. + * + *

Embeddable component used for aggregate measurement values with units and timestamps. + * All fields are optional (nullable) per ESPI 4.0 specification. + * + *

Per ESPI 4.0 espi.xsd lines 1094-1129. + * + *

Note: JAXB annotations are on SummaryMeasurementDto for XML marshalling. + * This entity class is for JPA persistence only. + * + * @see ESPI Specification + */ @Embeddable @Getter @Setter @NoArgsConstructor @AllArgsConstructor +@EqualsAndHashCode public class SummaryMeasurement { - private String powerOfTenMultiplier; + /** + * The multiplier part of the unit of measure, e.g. "kilo" (k). + * + *

Optional field (nullable). Type: UnitMultiplierKind enum. + * XSD: espi.xsd line 1101 + */ + @Column(name = "power_of_ten_multiplier") + @Enumerated(EnumType.STRING) + private UnitMultiplierKind powerOfTenMultiplier; + /** + * The date and time (if needed) of the summary measurement. + * + *

Optional field (nullable). Type: TimeType (seconds since Unix epoch). + * XSD: espi.xsd line 1106 + */ + @Column(name = "time_stamp") private Long timeStamp; - private String uom; + /** + * The units of the reading, e.g. "Wh". + * + *

Optional field (nullable). Type: UnitSymbolKind enum. + * XSD: espi.xsd line 1111 + */ + @Column(name = "uom") + @Enumerated(EnumType.STRING) + private UnitSymbolKind uom; + /** + * The value of the summary measurement. + * + *

Optional field (nullable). Type: Int48 (48-bit signed integer). + * XSD: espi.xsd line 1116 + */ + @Column(name = "value") private Long value; + /** + * Reference URI to a full ReadingType resource. + * + *

Optional field (nullable). Type: xs:anyURI. + * XSD: espi.xsd line 1121 + */ + @Column(name = "reading_type_ref") private String readingTypeRef; } \ No newline at end of file diff --git a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/usage/UsageSummaryEntity.java b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/usage/UsageSummaryEntity.java index a4a82558..fe2473fb 100644 --- a/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/usage/UsageSummaryEntity.java +++ b/openespi-common/src/main/java/org/greenbuttonalliance/espi/common/domain/usage/UsageSummaryEntity.java @@ -625,12 +625,12 @@ public Double getCostAdditionalLastPeriodInDollars() { /** * Gets the commodity type being measured based on UOM. - * + * * @return commodity type description */ public String getCommodityType() { if (overallConsumptionLastPeriod != null && overallConsumptionLastPeriod.getUom() != null) { - String uom = overallConsumptionLastPeriod.getUom(); + String uom = overallConsumptionLastPeriod.getUom().name(); if (uom.contains("WH") || uom.contains("W")) return "Electricity"; if (uom.contains("BTU") || uom.contains("THERM")) return "Gas"; if (uom.contains("GAL") || uom.contains("L")) return "Water"; diff --git a/openespi-common/src/main/resources/db/migration/V1__Create_Base_Tables.sql b/openespi-common/src/main/resources/db/migration/V1__Create_Base_Tables.sql index a7679257..ceb03a38 100644 --- a/openespi-common/src/main/resources/db/migration/V1__Create_Base_Tables.sql +++ b/openespi-common/src/main/resources/db/migration/V1__Create_Base_Tables.sql @@ -246,8 +246,8 @@ CREATE TABLE reading_types tou VARCHAR(50), uom VARCHAR(50), cpp VARCHAR(50), - interharmonic_numerator BIGINT, - interharmonic_denominator BIGINT, + interharmonic_numerator DECIMAL(38,0), + interharmonic_denominator DECIMAL(38,0), measuring_period VARCHAR(50), argument_numerator DECIMAL(38,0), argument_denominator DECIMAL(38,0) diff --git a/openespi-common/src/main/resources/schema/ESPI_4.1/customer_4.1.xsd b/openespi-common/src/main/resources/schema/ESPI_4.1/customer_4.1.xsd index 186517e0..d8ddd5d9 100755 --- a/openespi-common/src/main/resources/schema/ESPI_4.1/customer_4.1.xsd +++ b/openespi-common/src/main/resources/schema/ESPI_4.1/customer_4.1.xsd @@ -633,8 +633,13 @@ Additional Complex Types Formal agreement between two parties defining the terms and conditions for a set of services. The specifics of the services are, in turn, defined via one or more service agreements. - + + + + Basic agreement information. + + Date this agreement was consummated among associated persons and/or organisations. @@ -3161,9 +3166,6 @@ Global Elements - @@ -3182,9 +3184,6 @@ Global Elements - @@ -3204,7 +3203,4 @@ Global Elements - \ No newline at end of file diff --git a/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/LineItemRepositoryTest.java b/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/LineItemRepositoryTest.java index 8e8939da..cd23361c 100644 --- a/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/LineItemRepositoryTest.java +++ b/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/LineItemRepositoryTest.java @@ -21,6 +21,8 @@ import org.greenbuttonalliance.espi.common.domain.common.DateTimeInterval; import org.greenbuttonalliance.espi.common.domain.common.SummaryMeasurement; import org.greenbuttonalliance.espi.common.domain.usage.LineItemEntity; +import org.greenbuttonalliance.espi.common.domain.usage.enums.UnitMultiplierKind; +import org.greenbuttonalliance.espi.common.domain.usage.enums.UnitSymbolKind; import org.greenbuttonalliance.espi.common.domain.usage.UsagePointEntity; import org.greenbuttonalliance.espi.common.domain.usage.UsageSummaryEntity; import org.greenbuttonalliance.espi.common.test.BaseRepositoryTest; @@ -112,8 +114,14 @@ void shouldSaveLineItemWithAllOptionalFields() { usageSummary.setUsagePoint(savedUsagePoint); UsageSummaryEntity savedUsageSummary = usageSummaryRepository.save(usageSummary); - SummaryMeasurement measurement = new SummaryMeasurement("3", 1641000000L, "Wh", 15000L, null); - DateTimeInterval itemPeriod = new DateTimeInterval(1640995200L, 86400L); + SummaryMeasurement measurement = new SummaryMeasurement( + UnitMultiplierKind.fromValue(3), + 1641000000L, + UnitSymbolKind.WH, + 15000L, + null + ); + DateTimeInterval itemPeriod = new DateTimeInterval(86400L, 1640995200L); LineItemEntity lineItem = new LineItemEntity(); lineItem.setAmount(15000L); diff --git a/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/ReadingTypeRepositoryTest.java b/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/ReadingTypeRepositoryTest.java index 64f4db84..a13b9e38 100644 --- a/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/ReadingTypeRepositoryTest.java +++ b/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/ReadingTypeRepositoryTest.java @@ -25,6 +25,8 @@ import org.greenbuttonalliance.espi.common.domain.common.ReadingInterharmonic; import org.greenbuttonalliance.espi.common.domain.common.ServiceCategory; import org.greenbuttonalliance.espi.common.test.BaseRepositoryTest; + +import java.math.BigInteger; import org.greenbuttonalliance.espi.common.test.TestDataBuilders; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -228,10 +230,10 @@ void shouldSaveReadingTypeWithReadingInterharmonicEmbeddedObjects() { // Create ReadingInterharmonic for interharmonic ReadingInterharmonic interharmonic = new ReadingInterharmonic(); - - // Set Long values directly - interharmonic.setNumerator(50L); - interharmonic.setDenominator(1L); + + // Set BigInteger values directly + interharmonic.setNumerator(BigInteger.valueOf(50L)); + interharmonic.setDenominator(BigInteger.valueOf(1L)); readingType.setInterharmonic(interharmonic); diff --git a/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/UsageSummaryRepositoryTest.java b/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/UsageSummaryRepositoryTest.java index 552d330c..9812c253 100644 --- a/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/UsageSummaryRepositoryTest.java +++ b/openespi-common/src/test/java/org/greenbuttonalliance/espi/common/repositories/usage/UsageSummaryRepositoryTest.java @@ -22,6 +22,8 @@ import org.greenbuttonalliance.espi.common.domain.common.ServiceCategory; import org.greenbuttonalliance.espi.common.domain.common.SummaryMeasurement; import org.greenbuttonalliance.espi.common.domain.usage.LineItemEntity; +import org.greenbuttonalliance.espi.common.domain.usage.enums.UnitMultiplierKind; +import org.greenbuttonalliance.espi.common.domain.usage.enums.UnitSymbolKind; import org.greenbuttonalliance.espi.common.domain.usage.RetailCustomerEntity; import org.greenbuttonalliance.espi.common.domain.usage.UsagePointEntity; import org.greenbuttonalliance.espi.common.domain.usage.UsageSummaryEntity; @@ -95,9 +97,9 @@ private DateTimeInterval createValidDateTimeInterval() { */ private SummaryMeasurement createValidSummaryMeasurement() { SummaryMeasurement measurement = new SummaryMeasurement(); - measurement.setPowerOfTenMultiplier("0"); + measurement.setPowerOfTenMultiplier(UnitMultiplierKind.fromValue(0)); // None measurement.setTimeStamp(randomOffsetDateTime().toEpochSecond()); - measurement.setUom("72"); // Wh + measurement.setUom(UnitSymbolKind.fromValue(72)); // Wh measurement.setValue(faker.number().numberBetween(1000L, 50000L)); measurement.setReadingTypeRef("https://api.example.com/ReadingType/" + randomUuid()); return measurement; @@ -381,12 +383,12 @@ void shouldPersistAndRetrieveSummaryMeasurementObjectsCorrectly() { SummaryMeasurement overallConsumption = createValidSummaryMeasurement(); overallConsumption.setValue(15000L); - overallConsumption.setUom("72"); // Wh + overallConsumption.setUom(UnitSymbolKind.fromValue(72)); // Wh summary.setOverallConsumptionLastPeriod(overallConsumption); SummaryMeasurement peakDemand = createValidSummaryMeasurement(); peakDemand.setValue(5000L); - peakDemand.setUom("38"); // W + peakDemand.setUom(UnitSymbolKind.fromValue(38)); // W summary.setPeakDemand(peakDemand); // Act @@ -397,10 +399,10 @@ void shouldPersistAndRetrieveSummaryMeasurementObjectsCorrectly() { assertThat(retrieved).isPresent(); assertThat(retrieved.get().getOverallConsumptionLastPeriod()).isNotNull(); assertThat(retrieved.get().getOverallConsumptionLastPeriod().getValue()).isEqualTo(15000L); - assertThat(retrieved.get().getOverallConsumptionLastPeriod().getUom()).isEqualTo("72"); + assertThat(retrieved.get().getOverallConsumptionLastPeriod().getUom()).isEqualTo(UnitSymbolKind.fromValue(72)); // Wh (UInt16: 72) assertThat(retrieved.get().getPeakDemand()).isNotNull(); assertThat(retrieved.get().getPeakDemand().getValue()).isEqualTo(5000L); - assertThat(retrieved.get().getPeakDemand().getUom()).isEqualTo("38"); + assertThat(retrieved.get().getPeakDemand().getUom()).isEqualTo(UnitSymbolKind.fromValue(38)); // W (UInt16: 38) } @Test