fix(selfop): preserve exact diagnostic decimals in JSON evidence
This commit is contained in:
+34
-2
@@ -5,6 +5,14 @@ import static com.baiyue.lastleg.selfoperated.analytics.diagnostic.QuantityDiagn
|
||||
import com.baiyue.lastleg.selfoperated.analytics.model.SelfopSyncTask;
|
||||
import com.baiyue.lastleg.selfoperated.analytics.model.SelfopCollectionPolicy;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import javax.sql.DataSource;
|
||||
@@ -37,7 +45,7 @@ public class QuantityDiagnosticService {
|
||||
|
||||
@Autowired
|
||||
public QuantityDiagnosticService(DataSource source, ObjectMapper json, QuantityDiagnosticProperties config) {
|
||||
this.json=json.copy().disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
this.json=storageMapper(json);
|
||||
this.config=config; this.clock=Clock.systemUTC();
|
||||
// Separate, bounded connection acquisition. Diagnostics cannot exhaust the collection pool.
|
||||
if(config.enabled()) {
|
||||
@@ -55,7 +63,7 @@ public class QuantityDiagnosticService {
|
||||
}
|
||||
QuantityDiagnosticService(JdbcTemplate jdbc,PlatformTransactionManager manager,ObjectMapper json,
|
||||
QuantityDiagnosticProperties config,Clock clock) {
|
||||
this.jdbc=jdbc;this.json=json.copy().disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
this.jdbc=jdbc;this.json=storageMapper(json);
|
||||
this.config=config;this.clock=clock;tx=new TransactionTemplate(manager);tx.setTimeout(3);
|
||||
}
|
||||
@PreDestroy public void close(){if(pool!=null)pool.close();}
|
||||
@@ -204,6 +212,30 @@ public class QuantityDiagnosticService {
|
||||
}
|
||||
private String encode(Object value){try{return json.writeValueAsString(value);}catch(Exception e){throw invalid("DIAGNOSTIC_ENCODING_FAILED");}}
|
||||
private <T>T decode(String value,Class<T> type){try{return json.readValue(value,type);}catch(Exception e){throw new IllegalStateException("DIAGNOSTIC_STORAGE_INVALID");}}
|
||||
/** Storage-only codec. The controller and Integration wire codec continue using numeric BigDecimal. */
|
||||
private static ObjectMapper storageMapper(ObjectMapper source) {
|
||||
var module=new SimpleModule("quantity-diagnostic-storage-decimals");
|
||||
module.addSerializer(BigDecimal.class,new StdSerializer<BigDecimal>(BigDecimal.class) {
|
||||
@Override public void serialize(BigDecimal value,JsonGenerator generator,
|
||||
com.fasterxml.jackson.databind.SerializerProvider provider)throws IOException {
|
||||
generator.writeString(value.stripTrailingZeros().toPlainString());
|
||||
}
|
||||
});
|
||||
module.addDeserializer(BigDecimal.class,new StdDeserializer<BigDecimal>(BigDecimal.class) {
|
||||
@Override public BigDecimal deserialize(JsonParser parser,
|
||||
com.fasterxml.jackson.databind.DeserializationContext context)throws IOException {
|
||||
// New grants never read historical numeric evidence; no numeric fallback/coercion.
|
||||
if(!parser.hasToken(JsonToken.VALUE_STRING))throw new IOException("DIAGNOSTIC_STORAGE_DECIMAL_REQUIRED");
|
||||
String text=parser.getText();
|
||||
if(!text.matches("(?:0|[1-9][0-9]{0,31})(?:\\.[0-9]{1,6})?"))throw new IOException("DIAGNOSTIC_STORAGE_DECIMAL_INVALID");
|
||||
BigDecimal value=new BigDecimal(text);
|
||||
if(!text.equals(value.stripTrailingZeros().toPlainString()))throw new IOException("DIAGNOSTIC_STORAGE_DECIMAL_NOT_CANONICAL");
|
||||
return value;
|
||||
}
|
||||
});
|
||||
return source.copy().disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.registerModule(module);
|
||||
}
|
||||
private static int size(String s){return s.getBytes(StandardCharsets.UTF_8).length;}
|
||||
private static String hash(String s){try{return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(s.getBytes(StandardCharsets.UTF_8)));}catch(Exception e){throw new IllegalStateException(e);}}
|
||||
public record Pair(Event list,Event detail){}
|
||||
|
||||
Reference in New Issue
Block a user