Skip to content

Commit

Permalink
Remove use of ThreadLocal
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelbl committed Jul 16, 2023
1 parent 56fa576 commit 6f13f8d
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 77 deletions.
19 changes: 8 additions & 11 deletions generator/src/main/java/net/codecrete/qrbill/canvas/SVGCanvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public class SVGCanvas extends AbstractCanvas implements ByteArrayResult {
private double lastPositionY;
private StringBuilder path;
private int approxPathLength;
private final DecimalFormat numberFormat = new DecimalFormat("#.###", new DecimalFormatSymbols(Locale.UK));

private final DecimalFormat angleFormat = new DecimalFormat("#.#####", new DecimalFormatSymbols(Locale.UK));

/**
* Creates a new instance of the specified size.
Expand Down Expand Up @@ -235,7 +238,7 @@ public void setTransformation(double translateX, double translateY, double rotat
stream.write(formatCoordinate(-translateY));
if (rotate != 0) {
stream.write(") rotate(");
stream.write(ANGLE_FORMAT.get().format(-rotate / Math.PI * 180));
stream.write(angleFormat.format(-rotate / Math.PI * 180));
}
if (scaleX != 1 || scaleY != 1) {
stream.write(") scale(");
Expand Down Expand Up @@ -280,18 +283,12 @@ public void saveAs(Path path) throws IOException {
}
}

private static final ThreadLocal<DecimalFormat> NUMBER_FORMAT
= ThreadLocal.withInitial(() -> new DecimalFormat("#.###", new DecimalFormatSymbols(Locale.UK)));

private static final ThreadLocal<DecimalFormat> ANGLE_FORMAT
= ThreadLocal.withInitial(() -> new DecimalFormat("#.#####", new DecimalFormatSymbols(Locale.UK)));

private static String formatNumber(double value) {
return NUMBER_FORMAT.get().format(value);
private String formatNumber(double value) {
return numberFormat.format(value);
}

private static String formatCoordinate(double value) {
return NUMBER_FORMAT.get().format(value * MM_TO_PT);
private String formatCoordinate(double value) {
return numberFormat.format(value * MM_TO_PT);
}

private static String formatColor(int color) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
*/
public class BillTextFormatter {

private static final ThreadLocal<DecimalFormat> AMOUNT_DISPLAY_FORMAT = ThreadLocal.withInitial(() -> {
DecimalFormat format = new DecimalFormat("###,##0.00");
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
symbols.setDecimalSeparator('.');
symbols.setGroupingSeparator(' ');
format.setDecimalFormatSymbols(symbols);
return format;
});

private final Bill bill;

/**
Expand Down Expand Up @@ -168,7 +159,7 @@ public String getAdditionalInformation() {
}

private static String formatAmountForDisplay(BigDecimal amount) {
return AMOUNT_DISPLAY_FORMAT.get().format(amount);
return createAmountFormatter().format(amount);
}

private static String formatAddressForDisplay(Address address, boolean withCountryCode) {
Expand Down Expand Up @@ -251,4 +242,14 @@ private Address createReducedAddress(Address address) {

return reducedAddress;
}

private static DecimalFormat createAmountFormatter() {
DecimalFormat format = new DecimalFormat("###,##0.00");
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
symbols.setDecimalSeparator('.');
symbols.setGroupingSeparator(' ');
format.setDecimalFormatSymbols(symbols);
return format;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,17 @@ private void appendDataField(String value) {
textBuilder.append('\n').append(value);
}

private static final ThreadLocal<DecimalFormat> AMOUNT_FIELD_FORMAT = ThreadLocal.withInitial(() -> {
private static DecimalFormat createAmountFormatter() {
DecimalFormat format = new DecimalFormat("0.00");
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
symbols.setDecimalSeparator('.');
format.setDecimalFormatSymbols(symbols);
format.setParseBigDecimal(true);
return format;
});
}

private static String formatAmountForCode(BigDecimal amount) {
return AMOUNT_FIELD_FORMAT.get().format(amount);
return createAmountFormatter().format(amount);
}

// According to a letter from SIX dated August 5, 2020, only the major number (leading "02") should be checked
Expand Down Expand Up @@ -156,7 +156,7 @@ public static Bill decode(String text) {

if (lines[18].length() > 0) {
ParsePosition position = new ParsePosition(0);
BigDecimal amount = (BigDecimal) AMOUNT_FIELD_FORMAT.get().parse(lines[18], position);
BigDecimal amount = (BigDecimal) createAmountFormatter().parse(lines[18], position);
if (position.getIndex() == lines[18].length())
bill.setAmount(amount);
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,14 @@
//

package net.codecrete.qrbill.generator;
/// <summary>
/// Decodes structured bill information according to Swico S1 syntax.
/// <para>
/// The encoded bill information can be found in a Swiss QR bill in th field <c>StrdBkgInf</c>.
/// </para>
/// <para>
/// Also see http://swiss-qr-invoice.org/downloads/qr-bill-s1-syntax-de.pdf
/// </para>
/// </summary>

import net.codecrete.qrbill.generator.SwicoBillInformation.PaymentCondition;
import net.codecrete.qrbill.generator.SwicoBillInformation.RateDetail;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
Expand Down Expand Up @@ -58,8 +50,10 @@ public class SwicoS1Decoder {
private static final int PAYMENT_CONDITIONS_TAG = 40;


private NumberFormat numberFormat;


private SwicoS1Decoder() {
// don't instantiate
}

/**
Expand All @@ -72,6 +66,10 @@ private SwicoS1Decoder() {
* @return the decoded bill information (or {@code null} if no valid Swico bill information is found)
*/
static SwicoBillInformation decode(String billInfoText) {
return new SwicoS1Decoder().decodeIt(billInfoText);
}

private SwicoBillInformation decodeIt(String billInfoText) {
if (billInfoText == null || !billInfoText.startsWith("//S1/"))
return null;

Expand All @@ -98,7 +96,7 @@ static SwicoBillInformation decode(String billInfoText) {
return billInformation;
}

private static void decodeElement(SwicoBillInformation billInformation, int tag, String value) {
private void decodeElement(SwicoBillInformation billInformation, int tag, String value) {
if (value.length() == 0)
return;

Expand Down Expand Up @@ -156,7 +154,7 @@ private static void setVatDates(SwicoBillInformation billInformation, String val
}
}

private static void setVatRateDetails(SwicoBillInformation billInformation, String value) {
private void setVatRateDetails(SwicoBillInformation billInformation, String value) {
// Test for single VAT rate vs list of tuples
if (!value.contains(":") && !value.contains(";")) {
billInformation.setVatRate(getDecimalValue(value));
Expand All @@ -167,7 +165,7 @@ private static void setVatRateDetails(SwicoBillInformation billInformation, Stri
}
}

private static void setPaymentConditions(SwicoBillInformation billInformation, String value) {
private void setPaymentConditions(SwicoBillInformation billInformation, String value) {
// Split into tuples
String[] tuples = value.split(";");

Expand All @@ -188,7 +186,7 @@ private static void setPaymentConditions(SwicoBillInformation billInformation, S
billInformation.setPaymentConditions(list);
}

private static List<RateDetail> parseDetailList(String text) {
private List<RateDetail> parseDetailList(String text) {
// Split into tuples
String[] tuples = text.split(";");

Expand Down Expand Up @@ -245,15 +243,15 @@ private static Integer getIntValue(String intText) {
}
}

private static final ThreadLocal<DecimalFormat> SWICO_NUMBER_FORMAT = ThreadLocal.withInitial(() -> {
DecimalFormat format = new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.UK));
format.setParseBigDecimal(true);
return format;
});
private BigDecimal getDecimalValue(String decimalText) {
if (numberFormat == null) {
DecimalFormat format = new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.UK));
format.setParseBigDecimal(true);
numberFormat = format;
}

private static BigDecimal getDecimalValue(String decimalText) {
ParsePosition position = new ParsePosition(0);
BigDecimal decimal = (BigDecimal) SWICO_NUMBER_FORMAT.get().parse(decimalText, position);
BigDecimal decimal = (BigDecimal) numberFormat.parse(decimalText, position);
return (position.getIndex() == decimalText.length()) ? decimal : null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
*/
class SwicoS1Encoder {

private DecimalFormat numberFormat;

private SwicoS1Encoder() {
// may not instantiate
}

/**
Expand All @@ -41,6 +42,10 @@ private SwicoS1Encoder() {
* @return encoded bill information text
*/
static String encode(SwicoBillInformation billInfo) {
return new SwicoS1Encoder().encodeIt(billInfo);
}

private String encodeIt(SwicoBillInformation billInfo) {
StringBuilder sb = new StringBuilder();

sb.append("//S1");
Expand Down Expand Up @@ -88,21 +93,17 @@ private static String escapedText(String text) {
return text.replace("\\", "\\\\").replace("/", "\\/");
}

private static final DateTimeFormatter SWICO_DATE_FORMAT
= DateTimeFormatter.ofPattern("yyMMdd", Locale.UK);

private static String s1Date(LocalDate date) {
return date.format(SWICO_DATE_FORMAT);
return date.format(DATE_FORMAT);
}

private static final ThreadLocal<DecimalFormat> SWICO_NUMBER_FORMAT
= ThreadLocal.withInitial(() -> new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.UK)));

private static String s1Number(BigDecimal num) {
return SWICO_NUMBER_FORMAT.get().format(num);
private String s1Number(BigDecimal num) {
if (numberFormat == null)
numberFormat = new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.UK));
return numberFormat.format(num);
}

private static void appendRateDetailTupleList(StringBuilder sb, List<RateDetail> list) {
private void appendRateDetailTupleList(StringBuilder sb, List<RateDetail> list) {
boolean isFirst = true;
for (RateDetail e : list) {
if (!isFirst)
Expand All @@ -113,7 +114,7 @@ private static void appendRateDetailTupleList(StringBuilder sb, List<RateDetail>
}
}

private static void appendConditionTupleList(StringBuilder sb, List<PaymentCondition> list) {
private void appendConditionTupleList(StringBuilder sb, List<PaymentCondition> list) {
boolean isFirst = true;
for (PaymentCondition e : list) {
if (!isFirst)
Expand All @@ -123,4 +124,6 @@ private static void appendConditionTupleList(StringBuilder sb, List<PaymentCondi
sb.append(s1Number(e.getDiscount())).append(":").append(e.getDays());
}
}

private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyMMdd", Locale.UK);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import net.codecrete.qrbill.testhelper.SampleData;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
Expand Down Expand Up @@ -67,26 +69,11 @@ void nonQrIbanAndWhitespaceRef_ok() {
assertNull(validatedBill.getReference());
}

@Test
void invalidRef_refIsValidErr() {
bill = SampleData.getExample1();
bill.setReference("ABC");
validate();
assertSingleErrorMessage(ValidationConstants.FIELD_REFERENCE, ValidationConstants.KEY_REF_INVALID);
}

@Test
void invalidNumericRef_refIsValidErr() {
bill = SampleData.getExample1();
bill.setReference("1234567890");
validate();
assertSingleErrorMessage(ValidationConstants.FIELD_REFERENCE, ValidationConstants.KEY_REF_INVALID);
}

@Test
void invalidAlphaNumericRef_refIsValidErr() {
@ParameterizedTest
@ValueSource(strings = {"ABC", "1234567890", "123ABC7890"})
void invalidRef_refIsValidErr(String invalidReference) {
bill = SampleData.getExample1();
bill.setReference("123ABC7890");
bill.setReference(invalidReference);
validate();
assertSingleErrorMessage(ValidationConstants.FIELD_REFERENCE, ValidationConstants.KEY_REF_INVALID);
}
Expand Down

0 comments on commit 6f13f8d

Please sign in to comment.