You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2025/10/14 13:50:06 UTC

(juneau) branch master updated: JUNEAU-206 - Fix bug with @Beanp(format)

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 050d7118c3 JUNEAU-206 - Fix bug with @Beanp(format)
050d7118c3 is described below

commit 050d7118c3594e736750d628e6f44e677d35c7d4
Author: James Bognar <ja...@salesforce.com>
AuthorDate: Tue Oct 14 09:49:56 2025 -0400

    JUNEAU-206 - Fix bug with @Beanp(format)
---
 CLAUDE.md                                          |  5 ++
 .../java/org/apache/juneau/BeanPropertyMeta.java   |  4 ++
 juneau-docs/docs/release-notes/9.2.0.md            | 15 ++++++
 .../java/org/apache/juneau/html/Common_Test.java   | 54 +++++++++++++++++++++
 .../org/apache/juneau/http/header/Date_Test.java   |  2 +-
 .../http/remote/Remote_RequestAnnotation_Test.java |  2 +-
 .../java/org/apache/juneau/json/Common_Test.java   | 56 +++++++++++++++++++++-
 .../org/apache/juneau/xml/CommonParser_Test.java   |  2 +-
 .../java/org/apache/juneau/xml/Common_Test.java    | 54 +++++++++++++++++++++
 9 files changed, 190 insertions(+), 4 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 8e6f27c44b..73f0bef73e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -45,6 +45,11 @@ If you encounter situations where your code changes don't appear to be taking ef
 - Test results seem to reflect old code despite edits
 - Compilation succeeds but runtime behavior is wrong
 
+**Java Runtime Location:**
+If you can't find Java on the file system using standard commands, look for it in the `~/jdk` folder. For example:
+- Java 17 can be found at: `~/jdk/openjdk_17.0.14.0.101_17.57.18_aarch64/bin/java`
+- Use this path when you need to run Java commands directly
+
 ### 5. HTML5 Bean Enhancement Rules
 
 #### Javadoc Enhancement for HTML5 Beans
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index d522a9a75d..e68cc2e4e6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -194,6 +194,8 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					isUri |= (rawTypeMeta.isUri());
 				}
 				lp.forEach(x -> {
+					if (swap == null)
+						swap = getPropertySwap(x);
 					if (! x.properties().isEmpty())
 						properties = splita(x.properties());
 					addAll(bdClasses, x.dictionary());
@@ -213,6 +215,8 @@ public class BeanPropertyMeta implements Comparable<BeanPropertyMeta> {
 					rawTypeMeta = bc.resolveClassMeta(last(lp), getter.getGenericReturnType(), typeVarImpls);
 				isUri |= (rawTypeMeta.isUri() || bc.hasAnnotation(Uri.class, getter));
 				lp.forEach(x -> {
+					if (swap == null)
+						swap = getPropertySwap(x);
 					if (properties != null && ! x.properties().isEmpty())
 						properties = splita(x.properties());
 					addAll(bdClasses, x.dictionary());
diff --git a/juneau-docs/docs/release-notes/9.2.0.md b/juneau-docs/docs/release-notes/9.2.0.md
index c23c13857c..702ed8cfa0 100644
--- a/juneau-docs/docs/release-notes/9.2.0.md
+++ b/juneau-docs/docs/release-notes/9.2.0.md
@@ -371,6 +371,21 @@ Major changes include:
   
   **Note**: Disabling JSON tags can cause different data to be parsed (e.g., strings instead of numbers) since type information is not preserved in the XML.
 
+#### Bug Fixes
+
+- **@Beanp(format) Not Working**: Fixed a bug where the `@Beanp(format="...")` annotation was not applying `String.format()` patterns during bean serialization. The issue was caused by missing calls to `getPropertySwap()` when processing `@Beanp` annotations on fields and getter methods. This feature now correctly formats numeric fields using Java format strings (e.g., `@Beanp(format="%.2f")` for floating-point values, `@Beanp(format="%05d")` for zero-padded integers, `@Beanp(format="$%. [...]
+  
+  Example:
+  ```java
+  public class Product {
+      @Beanp(format="$%.2f")
+      public float price = 19.99f;  // Serializes as "$19.99"
+      
+      @Beanp(format="%05d")
+      public int id = 42;  // Serializes as "00042"
+  }
+  ```
+
 ### juneau-bct (NEW MODULE)
 
 #### Bean-Centric Testing Framework
diff --git a/juneau-utest/src/test/java/org/apache/juneau/html/Common_Test.java b/juneau-utest/src/test/java/org/apache/juneau/html/Common_Test.java
index db1f8a9925..f74f5ac321 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/html/Common_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/html/Common_Test.java
@@ -413,4 +413,58 @@ class Common_Test extends TestBase {
 			return ("J(f1: " + this.getF1() + ", f2: " + this.getF2() + ")");
 		}
 	}
+
+	//====================================================================================================
+	// @Beanp(format) tests
+	//====================================================================================================
+	
+	@Test
+	void a10_beanpFormat() throws Exception {
+		var s = HtmlSerializer.create().sq().sortProperties().addKeyValueTableHeaders().build();
+		
+		var bean = new K();
+		var html = s.serialize(bean);
+		
+		// Verify all formatted fields are serialized correctly
+		assertTrue(html.contains("<td>doubleField</td><td>2.718</td>"));
+		assertTrue(html.contains("<td>floatField</td><td>3.14</td>"));
+		assertTrue(html.contains("<td>floatWithCurrency</td><td>$19.99</td>"));
+		assertTrue(html.contains("<td>hexField</td><td>0xFF00FF</td>"));
+		assertTrue(html.contains("<td>intField</td><td>00042</td>"));
+		assertTrue(html.contains("<td>longField</td><td>0000001234567890</td>"));
+		assertTrue(html.contains("<td>name</td><td>Test</td>"));
+		assertTrue(html.contains("<td>privateField</td><td>9.88</td>"));
+		assertTrue(html.contains("<td>scientificField</td><td>6.022e+23</td>") || html.contains("<td>scientificField</td><td>6.022E+23</td>"));
+	}
+	
+	public static class K {
+		@Beanp(format="%.2f")
+		public float floatField = 3.14159f;
+		
+		@Beanp(format="$%.2f")
+		public float floatWithCurrency = 19.987f;
+		
+		@Beanp(format="%.3f")
+		public double doubleField = 2.71828;
+		
+		@Beanp(format="%05d")
+		public int intField = 42;
+		
+		@Beanp(format="%016d")
+		public long longField = 1234567890L;
+		
+		@Beanp(format="0x%06X")
+		public int hexField = 0xFF00FF;
+		
+		@Beanp(format="%.3e")
+		public double scientificField = 6.02214076e23;
+		
+		public String name = "Test";
+		
+		@Beanp(format="%.2f")
+		private float privateField = 9.876f;
+		
+		public float getPrivateField() { return privateField; }
+		public void setPrivateField(float f) { privateField = f; }
+	}
 }
\ No newline at end of file
diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/header/Date_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/header/Date_Test.java
index 5af13a56bf..f7819a1484 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/http/header/Date_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/http/header/Date_Test.java
@@ -34,7 +34,7 @@ import org.apache.juneau.rest.client.*;
 import org.apache.juneau.rest.mock.*;
 import org.junit.jupiter.api.*;
 
-class Date_Test  extends TestBase{
+class Date_Test extends TestBase {
 
 	private static final String HEADER = "Date";
 	private static final String VALUE = "Sat, 29 Oct 1994 19:43:31 GMT";
diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_RequestAnnotation_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_RequestAnnotation_Test.java
index 7f55d4420e..fb9db795ff 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_RequestAnnotation_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_RequestAnnotation_Test.java
@@ -29,7 +29,7 @@ import org.apache.juneau.rest.mock.*;
 import org.apache.juneau.utest.utils.*;
 import org.junit.jupiter.api.*;
 
-class Remote_RequestAnnotation_Test  extends TestBase{
+class Remote_RequestAnnotation_Test extends TestBase {
 
 	//-----------------------------------------------------------------------------------------------------------------
 	// Basic tests
diff --git a/juneau-utest/src/test/java/org/apache/juneau/json/Common_Test.java b/juneau-utest/src/test/java/org/apache/juneau/json/Common_Test.java
index 1aebb49608..58b6044da4 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/json/Common_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/json/Common_Test.java
@@ -27,7 +27,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
 import org.junit.jupiter.api.*;
 
-class Common_Test  extends TestBase{
+class Common_Test extends TestBase {
 
 	//====================================================================================================
 	// Trim nulls from beans
@@ -294,4 +294,58 @@ class Common_Test  extends TestBase{
 			return ("J(f1: " + this.getF1() + ", f2: " + this.getF2() + ")");
 		}
 	}
+
+	//====================================================================================================
+	// @Beanp(format) tests
+	//====================================================================================================
+
+	@Test
+	void a10_beanpFormat() throws Exception {
+		var s = JsonSerializer.create().json5().sortProperties().build();
+
+		var bean = new K();
+		var json = s.serialize(bean);
+
+		// Verify all formatted fields are serialized correctly
+		assertTrue(json.contains("floatField:'3.14'"));
+		assertTrue(json.contains("floatWithCurrency:'$19.99'"));
+		assertTrue(json.contains("doubleField:'2.718'"));
+		assertTrue(json.contains("privateField:'9.88'"));
+		assertTrue(json.contains("intField:'00042'"));
+		assertTrue(json.contains("longField:'0000001234567890'"));
+		assertTrue(json.contains("hexField:'0xFF00FF'"));
+		assertTrue(json.contains("scientificField:'6.022e+23'") || json.contains("scientificField:'6.022E+23'"));
+		assertTrue(json.contains("name:'Test'"));
+	}
+
+	public static class K {
+		@Beanp(format="%.2f")
+		public float floatField = 3.14159f;
+
+		@Beanp(format="$%.2f")
+		public float floatWithCurrency = 19.987f;
+
+		@Beanp(format="%.3f")
+		public double doubleField = 2.71828;
+
+		@Beanp(format="%05d")
+		public int intField = 42;
+
+		@Beanp(format="%016d")
+		public long longField = 1234567890L;
+
+		@Beanp(format="0x%06X")
+		public int hexField = 0xFF00FF;
+
+		@Beanp(format="%.3e")
+		public double scientificField = 6.02214076e23;
+
+		public String name = "Test";
+
+		@Beanp(format="%.2f")
+		private float privateField = 9.876f;
+
+		public float getPrivateField() { return privateField; }
+		public void setPrivateField(float f) { privateField = f; }
+	}
 }
\ No newline at end of file
diff --git a/juneau-utest/src/test/java/org/apache/juneau/xml/CommonParser_Test.java b/juneau-utest/src/test/java/org/apache/juneau/xml/CommonParser_Test.java
index 015b934ada..5a685ab73b 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/xml/CommonParser_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/xml/CommonParser_Test.java
@@ -27,7 +27,7 @@ import org.apache.juneau.parser.*;
 import org.junit.jupiter.api.*;
 
 @SuppressWarnings({"rawtypes","serial"})
-class CommonParser_Test  extends TestBase{
+class CommonParser_Test extends TestBase {
 
 	//====================================================================================================
 	// testFromSerializer
diff --git a/juneau-utest/src/test/java/org/apache/juneau/xml/Common_Test.java b/juneau-utest/src/test/java/org/apache/juneau/xml/Common_Test.java
index 961b7a4542..489aeea94f 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/xml/Common_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/xml/Common_Test.java
@@ -247,4 +247,58 @@ class Common_Test extends TestBase {
 		public String name = "baz";
 		public R1 r1;
 	}
+
+	//====================================================================================================
+	// @Beanp(format) tests
+	//====================================================================================================
+	
+	@Test
+	void a08_beanpFormat() throws Exception {
+		var s = XmlSerializer.create().sq().sortProperties().build();
+		
+		var bean = new K();
+		var xml = s.serialize(bean);
+		
+		// Verify all formatted fields are serialized correctly
+		assertTrue(xml.contains("<doubleField>2.718</doubleField>"));
+		assertTrue(xml.contains("<floatField>3.14</floatField>"));
+		assertTrue(xml.contains("<floatWithCurrency>$19.99</floatWithCurrency>"));
+		assertTrue(xml.contains("<hexField>0xFF00FF</hexField>"));
+		assertTrue(xml.contains("<intField>00042</intField>"));
+		assertTrue(xml.contains("<longField>0000001234567890</longField>"));
+		assertTrue(xml.contains("<name>Test</name>"));
+		assertTrue(xml.contains("<privateField>9.88</privateField>"));
+		assertTrue(xml.contains("<scientificField>6.022e+23</scientificField>") || xml.contains("<scientificField>6.022E+23</scientificField>"));
+	}
+	
+	public static class K {
+		@Beanp(format="%.2f")
+		public float floatField = 3.14159f;
+		
+		@Beanp(format="$%.2f")
+		public float floatWithCurrency = 19.987f;
+		
+		@Beanp(format="%.3f")
+		public double doubleField = 2.71828;
+		
+		@Beanp(format="%05d")
+		public int intField = 42;
+		
+		@Beanp(format="%016d")
+		public long longField = 1234567890L;
+		
+		@Beanp(format="0x%06X")
+		public int hexField = 0xFF00FF;
+		
+		@Beanp(format="%.3e")
+		public double scientificField = 6.02214076e23;
+		
+		public String name = "Test";
+		
+		@Beanp(format="%.2f")
+		private float privateField = 9.876f;
+		
+		public float getPrivateField() { return privateField; }
+		public void setPrivateField(float f) { privateField = f; }
+	}
 }
\ No newline at end of file