Prechádzať zdrojové kódy

additional json refactoring

Jason Rivard 3 rokov pred
rodič
commit
f9be9cced4
100 zmenil súbory, kde vykonal 466 pridanie a 498 odobranie
  1. 2 2
      data-service/src/main/java/password/pwm/receiver/FtpDataIngestor.java
  2. 3 3
      data-service/src/main/java/password/pwm/receiver/Storage.java
  3. 2 2
      data-service/src/main/java/password/pwm/receiver/TelemetryRestReceiver.java
  4. 1 1
      server/pom.xml
  5. 36 24
      server/src/main/java/password/pwm/PwmAboutProperty.java
  6. 7 6
      server/src/main/java/password/pwm/PwmApplication.java
  7. 2 2
      server/src/main/java/password/pwm/PwmEnvironment.java
  8. 3 3
      server/src/main/java/password/pwm/bean/LoginInfoBean.java
  9. 2 2
      server/src/main/java/password/pwm/bean/PasswordStatus.java
  10. 2 2
      server/src/main/java/password/pwm/bean/SmsItemBean.java
  11. 5 5
      server/src/main/java/password/pwm/bean/UserIdentity.java
  12. 2 1
      server/src/main/java/password/pwm/config/AppConfig.java
  13. 5 2
      server/src/main/java/password/pwm/config/PwmSettingCategory.java
  14. 3 3
      server/src/main/java/password/pwm/config/PwmSettingMetaDataReader.java
  15. 3 3
      server/src/main/java/password/pwm/config/PwmSettingTemplateSet.java
  16. 3 9
      server/src/main/java/password/pwm/config/function/ActionCertImportFunction.java
  17. 3 5
      server/src/main/java/password/pwm/config/option/WebServiceUsage.java
  18. 2 2
      server/src/main/java/password/pwm/config/profile/PwmPasswordPolicy.java
  19. 24 16
      server/src/main/java/password/pwm/config/stored/StoredConfigZipJsonSerializer.java
  20. 3 2
      server/src/main/java/password/pwm/config/value/AbstractValue.java
  21. 12 29
      server/src/main/java/password/pwm/config/value/ActionValue.java
  22. 2 2
      server/src/main/java/password/pwm/config/value/BooleanValue.java
  23. 4 4
      server/src/main/java/password/pwm/config/value/ChallengeValue.java
  24. 6 9
      server/src/main/java/password/pwm/config/value/CustomLinkValue.java
  25. 4 9
      server/src/main/java/password/pwm/config/value/EmailValue.java
  26. 5 4
      server/src/main/java/password/pwm/config/value/FileValue.java
  27. 8 11
      server/src/main/java/password/pwm/config/value/FormValue.java
  28. 2 2
      server/src/main/java/password/pwm/config/value/LocalizedStringArrayValue.java
  29. 2 5
      server/src/main/java/password/pwm/config/value/LocalizedStringValue.java
  30. 2 5
      server/src/main/java/password/pwm/config/value/NamedSecretValue.java
  31. 2 2
      server/src/main/java/password/pwm/config/value/NumericArrayValue.java
  32. 2 2
      server/src/main/java/password/pwm/config/value/NumericValue.java
  33. 4 7
      server/src/main/java/password/pwm/config/value/OptionListValue.java
  34. 2 2
      server/src/main/java/password/pwm/config/value/PasswordValue.java
  35. 3 3
      server/src/main/java/password/pwm/config/value/PrivateKeyValue.java
  36. 7 12
      server/src/main/java/password/pwm/config/value/RemoteWebServiceValue.java
  37. 3 3
      server/src/main/java/password/pwm/config/value/StoredValueEncoder.java
  38. 2 2
      server/src/main/java/password/pwm/config/value/StringArrayValue.java
  39. 2 2
      server/src/main/java/password/pwm/config/value/StringValue.java
  40. 4 4
      server/src/main/java/password/pwm/config/value/UserPermissionValue.java
  41. 6 6
      server/src/main/java/password/pwm/config/value/VerificationMethodValue.java
  42. 8 8
      server/src/main/java/password/pwm/config/value/data/ActionConfiguration.java
  43. 2 2
      server/src/main/java/password/pwm/config/value/data/CustomLinkConfiguration.java
  44. 2 2
      server/src/main/java/password/pwm/health/ApplianceStatusChecker.java
  45. 1 1
      server/src/main/java/password/pwm/http/HttpHeader.java
  46. 4 8
      server/src/main/java/password/pwm/http/HttpMethod.java
  47. 4 4
      server/src/main/java/password/pwm/http/PwmHttpRequestWrapper.java
  48. 2 2
      server/src/main/java/password/pwm/http/PwmResponse.java
  49. 2 2
      server/src/main/java/password/pwm/http/PwmSession.java
  50. 20 23
      server/src/main/java/password/pwm/http/servlet/ClientApiServlet.java
  51. 1 1
      server/src/main/java/password/pwm/http/servlet/LoginServlet.java
  52. 6 6
      server/src/main/java/password/pwm/http/servlet/SetupOtpServlet.java
  53. 1 1
      server/src/main/java/password/pwm/http/servlet/accountinfo/AccountInformationServlet.java
  54. 18 15
      server/src/main/java/password/pwm/http/servlet/admin/AdminServlet.java
  55. 8 6
      server/src/main/java/password/pwm/http/servlet/changepw/ChangePasswordServlet.java
  56. 22 23
      server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServlet.java
  57. 2 2
      server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServletUtils.java
  58. 2 2
      server/src/main/java/password/pwm/http/servlet/configeditor/data/NavTreeDataMaker.java
  59. 13 14
      server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideServlet.java
  60. 1 1
      server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerCertificatesServlet.java
  61. 1 1
      server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerServlet.java
  62. 2 1
      server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerWordlistServlet.java
  63. 3 3
      server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordServlet.java
  64. 3 3
      server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordStageProcessor.java
  65. 2 2
      server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordStateMachine.java
  66. 3 3
      server/src/main/java/password/pwm/http/servlet/forgottenpw/RemoteVerificationMethod.java
  67. 2 2
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskCardInfoBean.java
  68. 2 2
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskDetailInfoBean.java
  69. 20 20
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java
  70. 2 2
      server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationStateBean.java
  71. 6 6
      server/src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java
  72. 2 2
      server/src/main/java/password/pwm/http/servlet/newuser/NewUserUtils.java
  73. 4 3
      server/src/main/java/password/pwm/http/servlet/oauth/OAuthConsumerServlet.java
  74. 8 7
      server/src/main/java/password/pwm/http/servlet/oauth/OAuthMachine.java
  75. 4 4
      server/src/main/java/password/pwm/http/servlet/peoplesearch/PeopleSearchDataReader.java
  76. 10 10
      server/src/main/java/password/pwm/http/servlet/peoplesearch/PeopleSearchServlet.java
  77. 2 6
      server/src/main/java/password/pwm/http/servlet/resource/ResourceServletConfiguration.java
  78. 3 3
      server/src/main/java/password/pwm/http/servlet/setupresponses/SetupResponsesServlet.java
  79. 3 3
      server/src/main/java/password/pwm/http/servlet/updateprofile/UpdateProfileServlet.java
  80. 2 2
      server/src/main/java/password/pwm/http/state/CryptoCookieLoginImpl.java
  81. 3 6
      server/src/main/java/password/pwm/ldap/LdapConnectionService.java
  82. 2 2
      server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java
  83. 2 5
      server/src/main/java/password/pwm/ldap/auth/SessionAuthenticator.java
  84. 3 3
      server/src/main/java/password/pwm/ldap/schema/EdirSchemaExtender.java
  85. 2 2
      server/src/main/java/password/pwm/ldap/schema/SchemaDefinition.java
  86. 2 2
      server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java
  87. 6 6
      server/src/main/java/password/pwm/svc/cache/CacheService.java
  88. 4 4
      server/src/main/java/password/pwm/svc/cache/MemoryCacheStore.java
  89. 8 8
      server/src/main/java/password/pwm/svc/cr/CrService.java
  90. 2 2
      server/src/main/java/password/pwm/svc/cr/NMASCrOperator.java
  91. 3 3
      server/src/main/java/password/pwm/svc/db/DatabaseAccessorImpl.java
  92. 4 3
      server/src/main/java/password/pwm/svc/db/DatabaseService.java
  93. 3 3
      server/src/main/java/password/pwm/svc/db/JDBCDriverLoader.java
  94. 3 3
      server/src/main/java/password/pwm/svc/email/EmailService.java
  95. 2 2
      server/src/main/java/password/pwm/svc/event/AuditEvent.java
  96. 2 2
      server/src/main/java/password/pwm/svc/event/AuditRecordFactory.java
  97. 6 5
      server/src/main/java/password/pwm/svc/event/AuditService.java
  98. 2 2
      server/src/main/java/password/pwm/svc/event/AuditServiceClient.java
  99. 3 3
      server/src/main/java/password/pwm/svc/event/CEFAuditFormatter.java
  100. 4 4
      server/src/main/java/password/pwm/svc/event/JsonAuditFormatter.java

+ 2 - 2
data-service/src/main/java/password/pwm/receiver/FtpDataIngestor.java

@@ -25,7 +25,7 @@ import org.apache.commons.net.ftp.FTPFile;
 import org.apache.commons.net.ftp.FTPSClient;
 import org.apache.commons.net.ftp.FTPSClient;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.bean.TelemetryPublishBean;
 import password.pwm.bean.TelemetryPublishBean;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayInputStream;
@@ -126,7 +126,7 @@ class FtpDataIngestor
                     byteArrayOutputStream.write( buffer, 0, len );
                     byteArrayOutputStream.write( buffer, 0, len );
                 }
                 }
                 final String resultsStr = byteArrayOutputStream.toString( PwmConstants.DEFAULT_CHARSET.name() );
                 final String resultsStr = byteArrayOutputStream.toString( PwmConstants.DEFAULT_CHARSET.name() );
-                final TelemetryPublishBean bean = JsonUtil.deserialize( resultsStr, TelemetryPublishBean.class );
+                final TelemetryPublishBean bean = JsonFactory.get().deserialize( resultsStr, TelemetryPublishBean.class );
                 storage.store( bean );
                 storage.store( bean );
             }
             }
         }
         }

+ 3 - 3
data-service/src/main/java/password/pwm/receiver/Storage.java

@@ -31,7 +31,7 @@ import jetbrains.exodus.env.Store;
 import jetbrains.exodus.env.StoreConfig;
 import jetbrains.exodus.env.StoreConfig;
 import jetbrains.exodus.env.Transaction;
 import jetbrains.exodus.env.Transaction;
 import password.pwm.bean.TelemetryPublishBean;
 import password.pwm.bean.TelemetryPublishBean;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 
 
 import java.io.File;
 import java.io.File;
@@ -108,7 +108,7 @@ public class Storage
         environment.executeInTransaction( transaction ->
         environment.executeInTransaction( transaction ->
         {
         {
             final ByteIterable k = StringBinding.stringToEntry( value.getInstanceHash() );
             final ByteIterable k = StringBinding.stringToEntry( value.getInstanceHash() );
-            final ByteIterable v = StringBinding.stringToEntry( JsonUtil.serialize( value ) );
+            final ByteIterable v = StringBinding.stringToEntry( JsonFactory.get().serialize( value ) );
             store.put( transaction, k, v );
             store.put( transaction, k, v );
         } );
         } );
     }
     }
@@ -124,7 +124,7 @@ public class Storage
                 final String string = StringBinding.entryToString( new ArrayByteIterable( v ) );
                 final String string = StringBinding.entryToString( new ArrayByteIterable( v ) );
                 if ( StringUtil.notEmpty( string ) )
                 if ( StringUtil.notEmpty( string ) )
                 {
                 {
-                    return JsonUtil.deserialize( string, TelemetryPublishBean.class );
+                    return JsonFactory.get().deserialize( string, TelemetryPublishBean.class );
                 }
                 }
             }
             }
             return null;
             return null;

+ 2 - 2
data-service/src/main/java/password/pwm/receiver/TelemetryRestReceiver.java

@@ -27,7 +27,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmHttpRequestWrapper;
 import password.pwm.http.PwmHttpRequestWrapper;
 import password.pwm.i18n.Message;
 import password.pwm.i18n.Message;
 import password.pwm.util.ServletUtility;
 import password.pwm.util.ServletUtility;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.ws.server.RestResultBean;
 import password.pwm.ws.server.RestResultBean;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
@@ -55,7 +55,7 @@ public class TelemetryRestReceiver extends HttpServlet
         {
         {
             resp.setHeader( "Content", "application/json" );
             resp.setHeader( "Content", "application/json" );
             final String input = ServletUtility.readRequestBodyAsString( req, 1024 * 1024 );
             final String input = ServletUtility.readRequestBodyAsString( req, 1024 * 1024 );
-            final TelemetryPublishBean telemetryPublishBean = JsonUtil.deserialize( input, TelemetryPublishBean.class );
+            final TelemetryPublishBean telemetryPublishBean = JsonFactory.get().deserialize( input, TelemetryPublishBean.class );
             final Storage storage = ContextManager.getContextManager( this.getServletContext() ).getApp().getStorage();
             final Storage storage = ContextManager.getContextManager( this.getServletContext() ).getApp().getStorage();
             storage.store( telemetryPublishBean );
             storage.store( telemetryPublishBean );
             resp.getWriter().print( RestResultBean.forSuccessMessage( null, null, null, Message.Success_Unknown ).toJson( jsonPrettyPrint ) );
             resp.getWriter().print( RestResultBean.forSuccessMessage( null, null, null, Message.Success_Unknown ).toJson( jsonPrettyPrint ) );

+ 1 - 1
server/pom.xml

@@ -209,7 +209,7 @@
         <dependency>
         <dependency>
             <groupId>com.github.ldapchai</groupId>
             <groupId>com.github.ldapchai</groupId>
             <artifactId>ldapchai</artifactId>
             <artifactId>ldapchai</artifactId>
-            <version>0.8.1</version>
+            <version>0.8.2-SNAPSHOT</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>org.apache.directory.api</groupId>
             <groupId>org.apache.directory.api</groupId>

+ 36 - 24
server/src/main/java/password/pwm/PwmAboutProperty.java

@@ -20,6 +20,7 @@
 
 
 package password.pwm;
 package password.pwm;
 
 
+import lombok.Value;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
 import password.pwm.ldap.LdapConnectionService;
 import password.pwm.ldap.LdapConnectionService;
@@ -35,9 +36,13 @@ import java.nio.charset.Charset;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchAlgorithmException;
 import java.time.Instant;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
 import java.util.Map;
 import java.util.Map;
+import java.util.Optional;
 import java.util.TreeMap;
 import java.util.TreeMap;
 import java.util.function.Function;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 
 public enum PwmAboutProperty
 public enum PwmAboutProperty
 {
 {
@@ -122,40 +127,47 @@ public enum PwmAboutProperty
 
 
     private static final PwmLogger LOGGER = PwmLogger.forClass( PwmAboutProperty.class );
     private static final PwmLogger LOGGER = PwmLogger.forClass( PwmAboutProperty.class );
 
 
+    @Value
+    private static class Pair<K, V>
+    {
+        private final K key;
+        private final V value;
+    }
+
     public static Map<PwmAboutProperty, String> makeInfoBean(
     public static Map<PwmAboutProperty, String> makeInfoBean(
             final PwmApplication pwmApplication
             final PwmApplication pwmApplication
     )
     )
     {
     {
-        final Map<String, String> aboutMap = new TreeMap<>();
+        return Collections.unmodifiableMap( EnumSet.allOf( PwmAboutProperty.class )
+                .stream()
+                .map( aboutProp -> new Pair<>( aboutProp, readAboutValue( pwmApplication, aboutProp ) ) )
+                .filter( entry -> entry.getValue().isPresent() )
+                .collect( Collectors.toMap(
+                        Pair::getKey,
+                        entry -> entry.getValue().get(),
+                        ( k, k2 ) -> k,
+                        () -> new EnumMap<>( PwmAboutProperty.class ) ) ) );
 
 
-        for ( final PwmAboutProperty pwmAboutProperty : PwmAboutProperty.values() )
+    }
+
+    private static Optional<String> readAboutValue( final PwmApplication pwmApplication, final PwmAboutProperty pwmAboutProperty )
+    {
+        final Function<PwmApplication, String> valueProvider = pwmAboutProperty.value;
+        if ( valueProvider != null )
         {
         {
-            final Function<PwmApplication, String> valueProvider = pwmAboutProperty.value;
-            if ( valueProvider != null )
+            try
             {
             {
-                try
-                {
-                    final String value = valueProvider.apply( pwmApplication );
-                    aboutMap.put( pwmAboutProperty.name(), value == null ? "" : value );
-                }
-                catch ( final Throwable t )
-                {
-                    if ( !( t instanceof NullPointerException ) )
-                    {
-                        aboutMap.put( pwmAboutProperty.name(), LocaleHelper.getLocalizedMessage( null, Display.Value_NotApplicable, null ) );
-                        LOGGER.trace( () -> "error generating about value for '" + pwmAboutProperty.name() + "', error: " + t.getMessage() );
-                    }
-                }
+                final String value = valueProvider.apply( pwmApplication );
+                return Optional.ofNullable( value );
+            }
+            catch ( final Exception t )
+            {
+                LOGGER.trace( () -> "error generating about value for '" + pwmAboutProperty.name() + "', error: " + t.getMessage() );
+                return Optional.of( LocaleHelper.getLocalizedMessage( null, Display.Value_NotApplicable, pwmApplication.getConfig() ) );
             }
             }
         }
         }
 
 
-        final Map<PwmAboutProperty, String> returnMap = new TreeMap<>();
-        for ( final Map.Entry<String, String> entry : aboutMap.entrySet() )
-        {
-            returnMap.put( PwmAboutProperty.valueOf( entry.getKey() ), entry.getValue() );
-        }
-
-        return Collections.unmodifiableMap( returnMap );
+        return Optional.empty();
     }
     }
 
 
     private static String format( final Instant date )
     private static String format( final Instant date )

+ 7 - 6
server/src/main/java/password/pwm/PwmApplication.java

@@ -69,7 +69,7 @@ import password.pwm.util.cli.commands.ExportHttpsTomcatConfigCommand;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDB;
@@ -248,8 +248,9 @@ public class PwmApplication
         installTime = fetchInstallDate( startupTime );
         installTime = fetchInstallDate( startupTime );
         LOGGER.debug( () -> "this application instance first installed on " + JavaHelper.toIsoDate( installTime ) );
         LOGGER.debug( () -> "this application instance first installed on " + JavaHelper.toIsoDate( installTime ) );
 
 
-        LOGGER.debug( () -> "application environment flags: " + JsonUtil.serializeCollection( pwmEnvironment.getFlags() ) );
-        LOGGER.debug( () -> "application environment parameters: " + JsonUtil.serializeMap( pwmEnvironment.getParameters() ) );
+        LOGGER.debug( () -> "application environment flags: " + JsonFactory.get().serializeCollection( pwmEnvironment.getFlags() ) );
+        LOGGER.debug( () -> "application environment parameters: "
+                + JsonFactory.get().serializeMap( pwmEnvironment.getParameters(), PwmEnvironment.ApplicationParameter.class, String.class ) );
 
 
         pwmScheduler = new PwmScheduler( this );
         pwmScheduler = new PwmScheduler( this );
 
 
@@ -319,7 +320,7 @@ public class PwmApplication
         try
         try
         {
         {
             final Map<PwmAboutProperty, String> infoMap = PwmAboutProperty.makeInfoBean( this );
             final Map<PwmAboutProperty, String> infoMap = PwmAboutProperty.makeInfoBean( this );
-            LOGGER.trace( () ->  "application info: " + JsonUtil.serializeMap( infoMap ) );
+            LOGGER.trace( () ->  "application info: " + JsonFactory.get().serializeMap( infoMap, PwmAboutProperty.class, String.class ) );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
         {
         {
@@ -661,7 +662,7 @@ public class PwmApplication
             final Optional<String> strValue = localDB.get( LocalDB.DB.PWM_META, appAttribute.getKey() );
             final Optional<String> strValue = localDB.get( LocalDB.DB.PWM_META, appAttribute.getKey() );
             if ( strValue.isPresent() )
             if ( strValue.isPresent() )
             {
             {
-                return Optional.of( JsonUtil.deserialize( strValue.get(), returnClass ) );
+                return Optional.of( JsonFactory.get().deserialize( strValue.get(), returnClass ) );
             }
             }
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
@@ -694,7 +695,7 @@ public class PwmApplication
             }
             }
             else
             else
             {
             {
-                final String jsonValue = JsonUtil.serialize( value );
+                final String jsonValue = JsonFactory.get().serialize( value );
                 localDB.put( LocalDB.DB.PWM_META, appAttribute.getKey(), jsonValue );
                 localDB.put( LocalDB.DB.PWM_META, appAttribute.getKey(), jsonValue );
             }
             }
         }
         }

+ 2 - 2
server/src/main/java/password/pwm/PwmEnvironment.java

@@ -30,7 +30,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.ContextManager;
 import password.pwm.http.ContextManager;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -290,7 +290,7 @@ public class PwmEnvironment
 
 
             try
             try
             {
             {
-                final List<String> jsonValues = JsonUtil.deserializeStringList( input );
+                final List<String> jsonValues = JsonFactory.get().deserializeStringList( input );
                 final Set<ApplicationFlag> returnFlags = CollectionUtil.readEnumSetFromStringCollection( ApplicationFlag.class, jsonValues );
                 final Set<ApplicationFlag> returnFlags = CollectionUtil.readEnumSetFromStringCollection( ApplicationFlag.class, jsonValues );
                 return Collections.unmodifiableSet( returnFlags );
                 return Collections.unmodifiableSet( returnFlags );
             }
             }

+ 3 - 3
server/src/main/java/password/pwm/bean/LoginInfoBean.java

@@ -28,7 +28,7 @@ import password.pwm.ldap.auth.AuthenticationType;
 import password.pwm.ldap.auth.PwmAuthenticationSource;
 import password.pwm.ldap.auth.PwmAuthenticationSource;
 import password.pwm.util.BasicAuthInfo;
 import password.pwm.util.BasicAuthInfo;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 import java.time.Instant;
 import java.time.Instant;
@@ -118,8 +118,8 @@ public class LoginInfoBean implements Serializable
 
 
     public String toDebugString( ) throws PwmUnrecoverableException
     public String toDebugString( ) throws PwmUnrecoverableException
     {
     {
-        final LoginInfoBean debugLoginCookieBean = JsonUtil.cloneUsingJson( this, LoginInfoBean.class );
+        final LoginInfoBean debugLoginCookieBean = JsonFactory.get().cloneUsingJson( this, LoginInfoBean.class );
         debugLoginCookieBean.setUserCurrentPassword( new PasswordData( PwmConstants.LOG_REMOVED_VALUE_REPLACEMENT ) );
         debugLoginCookieBean.setUserCurrentPassword( new PasswordData( PwmConstants.LOG_REMOVED_VALUE_REPLACEMENT ) );
-        return JsonUtil.serialize( debugLoginCookieBean );
+        return JsonFactory.get().serialize( debugLoginCookieBean );
     }
     }
 }
 }

+ 2 - 2
server/src/main/java/password/pwm/bean/PasswordStatus.java

@@ -22,7 +22,7 @@ package password.pwm.bean;
 
 
 import lombok.Builder;
 import lombok.Builder;
 import lombok.Value;
 import lombok.Value;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 
 
@@ -38,7 +38,7 @@ public class PasswordStatus implements Serializable
     @Override
     @Override
     public String toString( )
     public String toString( )
     {
     {
-        return JsonUtil.serialize( this );
+        return JsonFactory.get().serialize( this );
     }
     }
 
 
     public boolean isEffectivelyExpired( )
     public boolean isEffectivelyExpired( )

+ 2 - 2
server/src/main/java/password/pwm/bean/SmsItemBean.java

@@ -23,7 +23,7 @@ package password.pwm.bean;
 
 
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.Value;
 import lombok.Value;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 
 
@@ -37,6 +37,6 @@ public class SmsItemBean implements Serializable
 
 
     public String toString( )
     public String toString( )
     {
     {
-        return "SMS Item: " + JsonUtil.serialize( this );
+        return "SMS Item: " + JsonFactory.get().serialize( this );
     }
     }
 }
 }

+ 5 - 5
server/src/main/java/password/pwm/bean/UserIdentity.java

@@ -34,7 +34,7 @@ import password.pwm.svc.cache.CacheKey;
 import password.pwm.svc.cache.CachePolicy;
 import password.pwm.svc.cache.CachePolicy;
 import password.pwm.svc.cache.CacheService;
 import password.pwm.svc.cache.CacheService;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -153,7 +153,7 @@ public class UserIdentity implements Serializable, Comparable<UserIdentity>
         // generate key
         // generate key
         try
         try
         {
         {
-            final String jsonValue = JsonUtil.serialize( this );
+            final String jsonValue = JsonFactory.get().serialize( this );
             final String localValue = CRYPO_HEADER + pwmApplication.getSecureService().encryptToString( jsonValue );
             final String localValue = CRYPO_HEADER + pwmApplication.getSecureService().encryptToString( jsonValue );
             this.obfuscatedValue = localValue;
             this.obfuscatedValue = localValue;
             cacheService.put( cacheKey, CachePolicy.makePolicyWithExpiration( TimeDuration.DAY ), localValue );
             cacheService.put( cacheKey, CachePolicy.makePolicyWithExpiration( TimeDuration.DAY ), localValue );
@@ -167,7 +167,7 @@ public class UserIdentity implements Serializable, Comparable<UserIdentity>
 
 
     public String toDelimitedKey( )
     public String toDelimitedKey( )
     {
     {
-        return JsonUtil.serialize( this );
+        return JsonFactory.get().serialize( this );
     }
     }
 
 
     public String toDisplayString( )
     public String toDisplayString( )
@@ -192,7 +192,7 @@ public class UserIdentity implements Serializable, Comparable<UserIdentity>
         {
         {
             final String input = key.substring( CRYPO_HEADER.length() );
             final String input = key.substring( CRYPO_HEADER.length() );
             final String jsonValue = pwmApplication.getSecureService().decryptStringValue( input );
             final String jsonValue = pwmApplication.getSecureService().decryptStringValue( input );
-            return JsonUtil.deserialize( jsonValue, UserIdentity.class );
+            return JsonFactory.get().deserialize( jsonValue, UserIdentity.class );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
         {
         {
@@ -207,7 +207,7 @@ public class UserIdentity implements Serializable, Comparable<UserIdentity>
 
 
         try
         try
         {
         {
-            return JsonUtil.deserialize( key, UserIdentity.class );
+            return JsonFactory.get().deserialize( key, UserIdentity.class );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
         {
         {

+ 2 - 1
server/src/main/java/password/pwm/config/AppConfig.java

@@ -47,6 +47,7 @@ import password.pwm.util.secure.PwmSecurityKey;
 import java.security.cert.X509Certificate;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
@@ -166,7 +167,7 @@ public class AppConfig implements SettingReader
     public Map<AppProperty, String> readAllNonDefaultAppProperties( )
     public Map<AppProperty, String> readAllNonDefaultAppProperties( )
     {
     {
         final LinkedHashMap<AppProperty, String> nonDefaultProperties = new LinkedHashMap<>();
         final LinkedHashMap<AppProperty, String> nonDefaultProperties = new LinkedHashMap<>();
-        for ( final AppProperty loopProperty : AppProperty.values() )
+        for ( final AppProperty loopProperty : EnumSet.allOf( AppProperty.class ) )
         {
         {
             final String configuredValue = readAppProperty( loopProperty );
             final String configuredValue = readAppProperty( loopProperty );
             final String defaultValue = loopProperty.getDefaultValue();
             final String defaultValue = loopProperty.getDefaultValue();

+ 5 - 2
server/src/main/java/password/pwm/config/PwmSettingCategory.java

@@ -33,6 +33,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Comparator;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.Optional;
@@ -508,7 +509,8 @@ public enum PwmSettingCategory
 
 
         public static Set<PwmSettingCategory> readChildren( final PwmSettingCategory category )
         public static Set<PwmSettingCategory> readChildren( final PwmSettingCategory category )
         {
         {
-            final Set<PwmSettingCategory> categories = Arrays.stream( PwmSettingCategory.values() )
+            final Set<PwmSettingCategory> categories = EnumSet.allOf( PwmSettingCategory.class )
+                    .stream()
                     .filter( ( loopCategory ) -> loopCategory.getParent() == category )
                     .filter( ( loopCategory ) -> loopCategory.getParent() == category )
                     .collect( Collectors.toUnmodifiableSet() );
                     .collect( Collectors.toUnmodifiableSet() );
             return Collections.unmodifiableSet( CollectionUtil.copiedEnumSet( categories, PwmSettingCategory.class ) );
             return Collections.unmodifiableSet( CollectionUtil.copiedEnumSet( categories, PwmSettingCategory.class ) );
@@ -516,7 +518,8 @@ public enum PwmSettingCategory
 
 
         public static Set<PwmSetting> readSettings( final PwmSettingCategory category )
         public static Set<PwmSetting> readSettings( final PwmSettingCategory category )
         {
         {
-            final Set<PwmSetting> settings = Arrays.stream( PwmSetting.values() )
+            final Set<PwmSetting> settings = EnumSet.allOf( PwmSetting.class )
+                    .stream()
                     .filter( ( setting ) -> setting.getCategory() == category )
                     .filter( ( setting ) -> setting.getCategory() == category )
                     .collect( Collectors.toSet() );
                     .collect( Collectors.toSet() );
             return Collections.unmodifiableSet( CollectionUtil.copiedEnumSet( settings, PwmSetting.class ) );
             return Collections.unmodifiableSet( CollectionUtil.copiedEnumSet( settings, PwmSetting.class ) );

+ 3 - 3
server/src/main/java/password/pwm/config/PwmSettingMetaDataReader.java

@@ -168,14 +168,14 @@ public class PwmSettingMetaDataReader
     }
     }
 
 
     /**
     /**
-     * Not required for normal operation, but executing this gets all the enum values poopulated form XML source.  If run prior to users accessing the settings
+     * Not required for normal operation, but executing this gets all the enum values populated form XML source.  If run prior to users accessing the settings
      * module (particularly the config editor) it will increase the initial load performance significantly.  There are no side effects to calling this operation
      * module (particularly the config editor) it will increase the initial load performance significantly.  There are no side effects to calling this operation
      * other than cache population.
      * other than cache population.
      */
      */
     public static void initCache()
     public static void initCache()
     {
     {
         final Instant startTime = Instant.now();
         final Instant startTime = Instant.now();
-        for ( final PwmSetting pwmSetting : PwmSetting.values() )
+        for ( final PwmSetting pwmSetting : EnumSet.allOf( PwmSetting.class ) )
         {
         {
             pwmSetting.getProperties();
             pwmSetting.getProperties();
             pwmSetting.getFlags();
             pwmSetting.getFlags();
@@ -190,7 +190,7 @@ public class PwmSettingMetaDataReader
             pwmSetting.getLDAPPermissionInfo();
             pwmSetting.getLDAPPermissionInfo();
             pwmSetting.toMenuLocationDebug( null, PwmConstants.DEFAULT_LOCALE );
             pwmSetting.toMenuLocationDebug( null, PwmConstants.DEFAULT_LOCALE );
         }
         }
-        for ( final PwmSettingCategory pwmSettingCategory : PwmSettingCategory.values() )
+        for ( final PwmSettingCategory pwmSettingCategory : EnumSet.allOf( PwmSettingCategory.class ) )
         {
         {
             pwmSettingCategory.getLabel( PwmConstants.DEFAULT_LOCALE );
             pwmSettingCategory.getLabel( PwmConstants.DEFAULT_LOCALE );
             pwmSettingCategory.getDescription( PwmConstants.DEFAULT_LOCALE );
             pwmSettingCategory.getDescription( PwmConstants.DEFAULT_LOCALE );

+ 3 - 3
server/src/main/java/password/pwm/config/PwmSettingTemplateSet.java

@@ -25,8 +25,8 @@ import password.pwm.util.java.CollectionUtil;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.List;
 import java.util.Set;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
@@ -44,7 +44,7 @@ public class PwmSettingTemplateSet implements Serializable
                 .map( PwmSettingTemplate::getType )
                 .map( PwmSettingTemplate::getType )
                 .collect( Collectors.toSet() );
                 .collect( Collectors.toSet() );
 
 
-        workingSet.addAll( Arrays.stream( PwmSettingTemplate.Type.values() )
+        workingSet.addAll( EnumSet.allOf( PwmSettingTemplate.Type.class ).stream()
                 .filter( type -> !seenTypes.contains( type ) )
                 .filter( type -> !seenTypes.contains( type ) )
                 .map( PwmSettingTemplate.Type::getDefaultValue )
                 .map( PwmSettingTemplate.Type::getDefaultValue )
                 .collect( Collectors.toSet( ) ) );
                 .collect( Collectors.toSet( ) ) );
@@ -75,7 +75,7 @@ public class PwmSettingTemplateSet implements Serializable
     {
     {
         final List<PwmSettingTemplateSet> templateSets = new ArrayList<>();
         final List<PwmSettingTemplateSet> templateSets = new ArrayList<>();
 
 
-        for ( final PwmSettingTemplate template : PwmSettingTemplate.values() )
+        for ( final PwmSettingTemplate template : EnumSet.allOf( PwmSettingTemplate.class ) )
         {
         {
             final PwmSettingTemplateSet templateSet = new PwmSettingTemplateSet( Collections.singleton( template ) );
             final PwmSettingTemplateSet templateSet = new PwmSettingTemplateSet( Collections.singleton( template ) );
             templateSets.add( templateSet );
             templateSets.add( templateSet );

+ 3 - 9
server/src/main/java/password/pwm/config/function/ActionCertImportFunction.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.config.function;
 package password.pwm.config.function;
 
 
-import com.google.gson.reflect.TypeToken;
 import password.pwm.bean.UserIdentity;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigKey;
 import password.pwm.config.stored.StoredConfigKey;
@@ -34,7 +33,7 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.net.URI;
 import java.net.URI;
 import java.security.cert.X509Certificate;
 import java.security.cert.X509Certificate;
@@ -54,10 +53,7 @@ public class ActionCertImportFunction extends AbstractUriCertImportFunction
     )
     )
             throws PwmOperationalException, PwmUnrecoverableException
             throws PwmOperationalException, PwmUnrecoverableException
     {
     {
-        final Map<String, Integer> extraDataMap = JsonUtil.deserialize( extraData, new TypeToken<Map<String, Integer>>()
-        {
-        } );
-
+        final Map<String, Integer> extraDataMap = JsonFactory.get().deserializeMap( extraData, String.class, Integer.class );
         final PwmSetting pwmSetting = key.toPwmSetting();
         final PwmSetting pwmSetting = key.toPwmSetting();
 
 
         final StoredValue actionValue = StoredConfigurationUtil.getValueOrDefault( modifier.newStoredConfiguration(), key );
         final StoredValue actionValue = StoredConfigurationUtil.getValueOrDefault( modifier.newStoredConfiguration(), key );
@@ -99,9 +95,7 @@ public class ActionCertImportFunction extends AbstractUriCertImportFunction
     )
     )
             throws PwmOperationalException, PwmUnrecoverableException
             throws PwmOperationalException, PwmUnrecoverableException
     {
     {
-        final Map<String, Integer> extraDataMap = JsonUtil.deserialize( extraData, new TypeToken<Map<String, Integer>>()
-        {
-        } );
+        final Map<String, Integer> extraDataMap = JsonFactory.get().deserializeMap( extraData, String.class, Integer.class );
 
 
         final StoredValue actionValue = StoredConfigurationUtil.getValueOrDefault( modifier.newStoredConfiguration(), key );
         final StoredValue actionValue = StoredConfigurationUtil.getValueOrDefault( modifier.newStoredConfiguration(), key );
         final List<ActionConfiguration> actionConfigurations = ValueTypeConverter.valueToAction( key.toPwmSetting(), actionValue );
         final List<ActionConfiguration> actionConfigurations = ValueTypeConverter.valueToAction( key.toPwmSetting(), actionValue );

+ 3 - 5
server/src/main/java/password/pwm/config/option/WebServiceUsage.java

@@ -59,10 +59,8 @@ public enum WebServiceUsage
 
 
     public static Set<WebServiceUsage> forType( final RestAuthenticationType type )
     public static Set<WebServiceUsage> forType( final RestAuthenticationType type )
     {
     {
-        return Collections.unmodifiableSet(
-                Arrays.stream( WebServiceUsage.values() )
-                        .filter( webServiceUsage -> webServiceUsage.getTypes().contains( type ) )
-                        .collect( Collectors.toSet() )
-        );
+        return EnumSet.allOf( WebServiceUsage.class ).stream()
+                .filter( webServiceUsage -> webServiceUsage.getTypes().contains( type ) )
+                .collect( Collectors.toUnmodifiableSet() );
     }
     }
 }
 }

+ 2 - 2
server/src/main/java/password/pwm/config/profile/PwmPasswordPolicy.java

@@ -38,7 +38,7 @@ import password.pwm.health.HealthRecord;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -279,7 +279,7 @@ public class PwmPasswordPolicy implements Profile, Serializable
     @Override
     @Override
     public String toString( )
     public String toString( )
     {
     {
-        return "PwmPasswordPolicy" + ": " + JsonUtil.serialize( this );
+        return "PwmPasswordPolicy" + ": " + JsonFactory.get().serialize( this );
     }
     }
 
 
     public ChaiPasswordPolicy getChaiPasswordPolicy( )
     public ChaiPasswordPolicy getChaiPasswordPolicy( )

+ 24 - 16
server/src/main/java/password/pwm/config/stored/StoredConfigZipJsonSerializer.java

@@ -20,18 +20,18 @@
 
 
 package password.pwm.config.stored;
 package password.pwm.config.stored;
 
 
-import com.google.gson.reflect.TypeToken;
 import lombok.Value;
 import lombok.Value;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.PwmSettingSyntax;
-import password.pwm.config.value.StoredValue;
 import password.pwm.config.value.FileValue;
 import password.pwm.config.value.FileValue;
+import password.pwm.config.value.StoredValue;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonProvider;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.SecureEngine;
 import password.pwm.util.secure.SecureEngine;
@@ -88,7 +88,7 @@ public class StoredConfigZipJsonSerializer implements StoredConfigSerializer
                                 && key.toPwmSetting().getSyntax().equals( PwmSettingSyntax.FILE )
                                 && key.toPwmSetting().getSyntax().equals( PwmSettingSyntax.FILE )
                 )
                 )
                 {
                 {
-                    final SerializedFileValue tempValue = JsonUtil.deserialize( serializedValue.getValueData(), SerializedFileValue.class );
+                    final SerializedFileValue tempValue = JsonFactory.get().deserialize( serializedValue.getValueData(), SerializedFileValue.class );
                     final Map<FileValue.FileInformation, FileValue.FileContent> unstrippedMap = new HashMap<>();
                     final Map<FileValue.FileInformation, FileValue.FileContent> unstrippedMap = new HashMap<>();
 
 
                     for ( final Map.Entry<String, FileValue.FileInformation> entry : tempValue.getFileInformation().entrySet() )
                     for ( final Map.Entry<String, FileValue.FileInformation> entry : tempValue.getFileInformation().entrySet() )
@@ -146,23 +146,19 @@ public class StoredConfigZipJsonSerializer implements StoredConfigSerializer
             if ( SETTINGS_FILENAME.equals( zipEntry.getName() ) )
             if ( SETTINGS_FILENAME.equals( zipEntry.getName() ) )
             {
             {
                 final String stringData = JavaHelper.copyToString( zipInputStream );
                 final String stringData = JavaHelper.copyToString( zipInputStream );
-                final List<SerializedValue> readComponents = JsonUtil.deserialize( stringData, new TypeToken<List<SerializedValue>>()
-                {
-                } );
+                final List<SerializedValue> readComponents = JsonFactory.get().deserializeList( stringData, SerializedValue.class );
                 serializedValues.addAll( readComponents );
                 serializedValues.addAll( readComponents );
             }
             }
             else if ( META_VALUES_FILENAME.equals( zipEntry.getName() ) )
             else if ( META_VALUES_FILENAME.equals( zipEntry.getName() ) )
             {
             {
                 final String stringData = JavaHelper.copyToString( zipInputStream );
                 final String stringData = JavaHelper.copyToString( zipInputStream );
-                final List<SerializedValue> readMetaValues = JsonUtil.deserialize( stringData, new TypeToken<List<SerializedMetaValue>>()
-                {
-                } );
-                serializedValues.addAll( readMetaValues );
+                final List<SerializedMetaValue> readMetaValues = JsonFactory.get().deserializeList( stringData, SerializedMetaValue.class );
+                serializedMetaValues.addAll( readMetaValues );
             }
             }
             else if ( META_FILENAME.equals( zipEntry.getName() ) )
             else if ( META_FILENAME.equals( zipEntry.getName() ) )
             {
             {
                 final String stringData = JavaHelper.copyToString( zipInputStream );
                 final String stringData = JavaHelper.copyToString( zipInputStream );
-                metaData = JsonUtil.deserialize( stringData, MetaData.class );
+                metaData = JsonFactory.get().deserialize( stringData, MetaData.class );
             }
             }
             else if ( zipEntry.getName().endsWith( XREF_SUFFIX ) )
             else if ( zipEntry.getName().endsWith( XREF_SUFFIX ) )
             {
             {
@@ -191,18 +187,30 @@ public class StoredConfigZipJsonSerializer implements StoredConfigSerializer
 
 
         {
         {
             zipOutputStream.putNextEntry( new ZipEntry( SETTINGS_FILENAME ) );
             zipOutputStream.putNextEntry( new ZipEntry( SETTINGS_FILENAME ) );
-            JavaHelper.copy( JsonUtil.serializeCollection( intermediateRepresentation.getSerializedValues(), JsonUtil.Flag.PrettyPrint ), zipOutputStream );
+            JavaHelper.copy(
+                    JsonFactory.get().serializeCollection(
+                            intermediateRepresentation.getSerializedValues(),
+                            JsonProvider.Flag.PrettyPrint ),
+                    zipOutputStream );
         }
         }
 
 
         {
         {
             zipOutputStream.putNextEntry( new ZipEntry( META_VALUES_FILENAME ) );
             zipOutputStream.putNextEntry( new ZipEntry( META_VALUES_FILENAME ) );
-            JavaHelper.copy( JsonUtil.serializeCollection( intermediateRepresentation.getSerializedMetaValues(), JsonUtil.Flag.PrettyPrint ), zipOutputStream );
+            JavaHelper.copy(
+                    JsonFactory.get().serializeCollection(
+                            intermediateRepresentation.getSerializedMetaValues(),
+                            JsonProvider.Flag.PrettyPrint ),
+                    zipOutputStream );
         }
         }
 
 
         {
         {
             final MetaData metaData = new MetaData( storedConfiguration.createTime(), storedConfiguration.modifyTime(), "1" );
             final MetaData metaData = new MetaData( storedConfiguration.createTime(), storedConfiguration.modifyTime(), "1" );
             zipOutputStream.putNextEntry( new ZipEntry( META_FILENAME ) );
             zipOutputStream.putNextEntry( new ZipEntry( META_FILENAME ) );
-            JavaHelper.copy( JsonUtil.serialize( metaData, JsonUtil.Flag.PrettyPrint ), zipOutputStream );
+            JavaHelper.copy(
+                    JsonFactory.get().serialize(
+                            metaData,
+                            JsonProvider.Flag.PrettyPrint ),
+                    zipOutputStream );
         }
         }
 
 
         for ( final Map.Entry<String, ImmutableByteArray> entry : intermediateRepresentation.getExRefs().entrySet() )
         for ( final Map.Entry<String, ImmutableByteArray> entry : intermediateRepresentation.getExRefs().entrySet() )
@@ -254,7 +262,7 @@ public class StoredConfigZipJsonSerializer implements StoredConfigSerializer
                     value = storedValue.get();
                     value = storedValue.get();
                     syntax = key.getSyntax();
                     syntax = key.getSyntax();
                 }
                 }
-                final String jsonValue = JsonUtil.serialize( ( Serializable ) value.toNativeObject() );
+                final String jsonValue = JsonFactory.get().serialize( ( Serializable ) value.toNativeObject() );
                 final SerializedValue storedComponent = new SerializedValue( key, syntax, jsonValue );
                 final SerializedValue storedComponent = new SerializedValue( key, syntax, jsonValue );
                 serializedValues.add( storedComponent );
                 serializedValues.add( storedComponent );
             }
             }

+ 3 - 2
server/src/main/java/password/pwm/config/value/AbstractValue.java

@@ -25,7 +25,8 @@ import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.http.bean.ImmutableByteArray;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonProvider;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlDocument;
 import password.pwm.util.java.XmlDocument;
@@ -67,7 +68,7 @@ public abstract class AbstractValue implements StoredValue
     @Override
     @Override
     public String toDebugString( final Locale locale )
     public String toDebugString( final Locale locale )
     {
     {
-        return JsonUtil.serialize( ( Serializable ) this.toNativeObject(), JsonUtil.Flag.PrettyPrint );
+        return JsonFactory.get().serialize( ( Serializable ) this.toNativeObject(), JsonProvider.Flag.PrettyPrint );
     }
     }
 
 
     @Override
     @Override

+ 12 - 29
server/src/main/java/password/pwm/config/value/ActionValue.java

@@ -30,10 +30,10 @@ import password.pwm.config.value.data.ActionConfiguration;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.X509Utils;
 import password.pwm.util.secure.X509Utils;
@@ -58,7 +58,7 @@ public class ActionValue extends AbstractValue implements StoredValue
 
 
     public ActionValue( final List<ActionConfiguration> values )
     public ActionValue( final List<ActionConfiguration> values )
     {
     {
-        this.values = Collections.unmodifiableList( values );
+        this.values = List.copyOf( CollectionUtil.stripNulls( values ) );
     }
     }
 
 
     public static StoredValueFactory factory( )
     public static StoredValueFactory factory( )
@@ -68,25 +68,9 @@ public class ActionValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public ActionValue fromJson( final String input )
             public ActionValue fromJson( final String input )
             {
             {
-                if ( input == null )
-                {
-                    return new ActionValue( Collections.emptyList() );
-                }
-                else
-                {
-                    List<ActionConfiguration> srcList = JsonUtil.deserialize( input,
-                            new TypeToken<List<ActionConfiguration>>()
-                            {
-                            }
-                    );
-
-                    srcList = srcList == null ? Collections.emptyList() : srcList;
-                    while ( srcList.contains( null ) )
-                    {
-                        srcList.remove( null );
-                    }
-                    return new ActionValue( Collections.unmodifiableList( srcList ) );
-                }
+                return input == null
+                        ? new ActionValue( Collections.emptyList() )
+                        : new ActionValue( JsonFactory.get().deserializeList( input, ActionConfiguration.class ) );
             }
             }
 
 
             @Override
             @Override
@@ -121,7 +105,7 @@ public class ActionValue extends AbstractValue implements StoredValue
                             }
                             }
                             else
                             else
                             {
                             {
-                                final ActionConfiguration.ActionConfigurationOldVersion1 parsedAc = JsonUtil
+                                final ActionConfiguration.ActionConfigurationOldVersion1 parsedAc = JsonFactory.get()
                                         .deserialize( stringValue.get(), ActionConfiguration.ActionConfigurationOldVersion1.class );
                                         .deserialize( stringValue.get(), ActionConfiguration.ActionConfigurationOldVersion1.class );
                                 if ( parsedAc != null )
                                 if ( parsedAc != null )
                                 {
                                 {
@@ -138,7 +122,7 @@ public class ActionValue extends AbstractValue implements StoredValue
                         }
                         }
                         else if ( syntaxVersion == 2 )
                         else if ( syntaxVersion == 2 )
                         {
                         {
-                            final ActionConfiguration value = JsonUtil.deserialize( stringValue.get(), ActionConfiguration.class );
+                            final ActionConfiguration value = JsonFactory.get().deserialize( stringValue.get(), ActionConfiguration.class );
                             final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>();
                             final List<ActionConfiguration.WebAction> clonedWebActions = new ArrayList<>();
                             for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
                             for ( final ActionConfiguration.WebAction webAction : value.getWebActions() )
                             {
                             {
@@ -218,7 +202,7 @@ public class ActionValue extends AbstractValue implements StoredValue
 
 
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
 
 
-            valueElement.addText( JsonUtil.serialize( clonedAction ) );
+            valueElement.addText( JsonFactory.get().serialize( clonedAction ) );
             returnList.add( valueElement );
             returnList.add( valueElement );
         }
         }
         return returnList;
         return returnList;
@@ -291,6 +275,7 @@ public class ActionValue extends AbstractValue implements StoredValue
         return output;
         return output;
     }
     }
 
 
+
     @Override
     @Override
     public String toDebugString( final Locale locale )
     public String toDebugString( final Locale locale )
     {
     {
@@ -308,7 +293,7 @@ public class ActionValue extends AbstractValue implements StoredValue
                 sb.append( "\n   WebServiceAction: " );
                 sb.append( "\n   WebServiceAction: " );
                 sb.append( "\n    method=" ).append( webAction.getMethod() );
                 sb.append( "\n    method=" ).append( webAction.getMethod() );
                 sb.append( "\n    url=" ).append( webAction.getUrl() );
                 sb.append( "\n    url=" ).append( webAction.getUrl() );
-                sb.append( "\n    headers=" ).append( JsonUtil.serializeMap( webAction.getHeaders() ) );
+                sb.append( "\n    headers=" ).append( JsonFactory.get().serializeMap( webAction.getHeaders() ) );
                 sb.append( "\n    username=" ).append( webAction.getUsername() );
                 sb.append( "\n    username=" ).append( webAction.getUsername() );
                 sb.append( "\n    password=" ).append(
                 sb.append( "\n    password=" ).append(
                         StringUtil.isEmpty( webAction.getPassword() )
                         StringUtil.isEmpty( webAction.getPassword() )
@@ -341,7 +326,6 @@ public class ActionValue extends AbstractValue implements StoredValue
         return sb.toString();
         return sb.toString();
     }
     }
 
 
-
     /**
     /**
      * Convert to json map where the certificate values are replaced with debug info for display in the config editor.
      * Convert to json map where the certificate values are replaced with debug info for display in the config editor.
      *
      *
@@ -349,8 +333,8 @@ public class ActionValue extends AbstractValue implements StoredValue
      */
      */
     public List<Map<String, Object>> toInfoMap( )
     public List<Map<String, Object>> toInfoMap( )
     {
     {
-        final String originalJson = JsonUtil.serializeCollection( values );
-        final List<Map<String, Object>> tempObj = JsonUtil.deserialize( originalJson, new TypeToken<List<Map<String, Object>>>()
+        final String originalJson = JsonFactory.get().serializeCollection( values );
+        final List<Map<String, Object>> tempObj = JsonFactory.get().deserialize( originalJson, new TypeToken<List<Map<String, Object>>>()
         {
         {
         } );
         } );
 
 
@@ -377,7 +361,6 @@ public class ActionValue extends AbstractValue implements StoredValue
             actionConfigurationCounter++;
             actionConfigurationCounter++;
         }
         }
 
 
-
         return tempObj;
         return tempObj;
     }
     }
 
 

+ 2 - 2
server/src/main/java/password/pwm/config/value/BooleanValue.java

@@ -25,7 +25,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -60,7 +60,7 @@ public class BooleanValue implements StoredValue
             @Override
             @Override
             public BooleanValue fromJson( final String value )
             public BooleanValue fromJson( final String value )
             {
             {
-                return BooleanValue.of( JsonUtil.deserialize( value, Boolean.class ) );
+                return BooleanValue.of( JsonFactory.get().deserialize( value, Boolean.class ) );
             }
             }
 
 
             @Override
             @Override

+ 4 - 4
server/src/main/java/password/pwm/config/value/ChallengeValue.java

@@ -29,7 +29,7 @@ import password.pwm.config.value.data.ChallengeItemConfiguration;
 import password.pwm.util.i18n.LocaleComparators;
 import password.pwm.util.i18n.LocaleComparators;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -81,7 +81,7 @@ public class ChallengeValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    Map<String, List<ChallengeItemConfiguration>> srcMap = JsonUtil.deserialize( input,
+                    Map<String, List<ChallengeItemConfiguration>> srcMap = JsonFactory.get().deserialize( input,
                             new TypeToken<Map<String, List<ChallengeItemConfiguration>>>()
                             new TypeToken<Map<String, List<ChallengeItemConfiguration>>>()
                             {
                             {
                             }
                             }
@@ -114,7 +114,7 @@ public class ChallengeValue extends AbstractValue implements StoredValue
                         }
                         }
                         else
                         else
                         {
                         {
-                            challengeItemBean = JsonUtil.deserialize( value, ChallengeItemConfiguration.class );
+                            challengeItemBean = JsonFactory.get().deserialize( value, ChallengeItemConfiguration.class );
                         }
                         }
                         if ( challengeItemBean != null )
                         if ( challengeItemBean != null )
                         {
                         {
@@ -141,7 +141,7 @@ public class ChallengeValue extends AbstractValue implements StoredValue
                 if ( value != null )
                 if ( value != null )
                 {
                 {
                     final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
                     final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
-                    valueElement.addText( JsonUtil.serialize( value ) );
+                    valueElement.addText( JsonFactory.get().serialize( value ) );
                     if ( locale != null && locale.length() > 0 )
                     if ( locale != null && locale.length() > 0 )
                     {
                     {
                         valueElement.setAttribute( "locale", locale );
                         valueElement.setAttribute( "locale", locale );

+ 6 - 9
server/src/main/java/password/pwm/config/value/CustomLinkValue.java

@@ -20,12 +20,11 @@
 
 
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
-import com.google.gson.reflect.TypeToken;
+import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.CustomLinkConfiguration;
 import password.pwm.config.value.data.CustomLinkConfiguration;
-import password.pwm.config.PwmSetting;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -59,9 +58,7 @@ public class CustomLinkValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    List<CustomLinkConfiguration> srcList = JsonUtil.deserialize( input, new TypeToken<List<CustomLinkConfiguration>>()
-                    {
-                    } );
+                    List<CustomLinkConfiguration> srcList = JsonFactory.get().deserializeList( input, CustomLinkConfiguration.class );
                     srcList = srcList == null ? Collections.emptyList() : srcList;
                     srcList = srcList == null ? Collections.emptyList() : srcList;
                     while ( srcList.contains( null ) )
                     while ( srcList.contains( null ) )
                     {
                     {
@@ -79,7 +76,7 @@ public class CustomLinkValue extends AbstractValue implements StoredValue
                 final List<CustomLinkConfiguration> values = new ArrayList<>();
                 final List<CustomLinkConfiguration> values = new ArrayList<>();
                 for ( final XmlElement loopValueElement  : valueElements )
                 for ( final XmlElement loopValueElement  : valueElements )
                 {
                 {
-                    loopValueElement.getText().ifPresent( value -> values.add( JsonUtil.deserialize( value, CustomLinkConfiguration.class ) ) );
+                    loopValueElement.getText().ifPresent( value -> values.add( JsonFactory.get().deserialize( value, CustomLinkConfiguration.class ) ) );
                 }
                 }
                 return new CustomLinkValue( values );
                 return new CustomLinkValue( values );
             }
             }
@@ -93,7 +90,7 @@ public class CustomLinkValue extends AbstractValue implements StoredValue
         for ( final CustomLinkConfiguration value : values )
         for ( final CustomLinkConfiguration value : values )
         {
         {
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
-            valueElement.addText( JsonUtil.serialize( value ) );
+            valueElement.addText( JsonFactory.get().serialize( value ) );
             returnList.add( valueElement );
             returnList.add( valueElement );
         }
         }
         return returnList;
         return returnList;
@@ -140,7 +137,7 @@ public class CustomLinkValue extends AbstractValue implements StoredValue
                 sb.append( "Link Name:" ).append( formRow.getName() ).append( "\n" );
                 sb.append( "Link Name:" ).append( formRow.getName() ).append( "\n" );
                 sb.append( " Type:" ).append( formRow.getType() );
                 sb.append( " Type:" ).append( formRow.getType() );
                 sb.append( "\n" );
                 sb.append( "\n" );
-                sb.append( " Description:" ).append( JsonUtil.serializeMap( formRow.getLabels() ) ).append( "\n" );
+                sb.append( " Description:" ).append( JsonFactory.get().serializeMap( formRow.getLabels() ) ).append( "\n" );
                 sb.append( " New Window:" ).append( formRow.isCustomLinkNewWindow() ).append( "\n" );
                 sb.append( " New Window:" ).append( formRow.isCustomLinkNewWindow() ).append( "\n" );
                 sb.append( " Url:" ).append( formRow.getCustomLinkUrl() ).append( "\n" );
                 sb.append( " Url:" ).append( formRow.getCustomLinkUrl() ).append( "\n" );
             }
             }

+ 4 - 9
server/src/main/java/password/pwm/config/value/EmailValue.java

@@ -20,12 +20,11 @@
 
 
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
-import com.google.gson.reflect.TypeToken;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.bean.EmailItemBean;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -62,11 +61,7 @@ public class EmailValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    Map<String, EmailItemBean> srcList = JsonUtil.deserialize( input,
-                            new TypeToken<Map<String, EmailItemBean>>()
-                            {
-                            }
-                    );
+                    Map<String, EmailItemBean> srcList = JsonFactory.get().deserializeMap( input, String.class, EmailItemBean.class );
 
 
                     srcList = srcList == null ? Collections.emptyMap() : srcList;
                     srcList = srcList == null ? Collections.emptyMap() : srcList;
                     srcList.remove( null );
                     srcList.remove( null );
@@ -89,7 +84,7 @@ public class EmailValue extends AbstractValue implements StoredValue
                         loopValueElement.getText().ifPresent( value ->
                         loopValueElement.getText().ifPresent( value ->
                         {
                         {
                             final String localeValue = loopValueElement.getAttributeValue( "locale" ).orElse( "" );
                             final String localeValue = loopValueElement.getAttributeValue( "locale" ).orElse( "" );
-                            values.put( localeValue, JsonUtil.deserialize( value, EmailItemBean.class ) );
+                            values.put( localeValue, JsonFactory.get().deserialize( value, EmailItemBean.class ) );
                         } );
                         } );
                     }
                     }
                 }
                 }
@@ -111,7 +106,7 @@ public class EmailValue extends AbstractValue implements StoredValue
             {
             {
                 valueElement.setAttribute( "locale", localeValue );
                 valueElement.setAttribute( "locale", localeValue );
             }
             }
-            valueElement.addText( JsonUtil.serialize( emailItemBean ) );
+            valueElement.addText( JsonFactory.get().serialize( emailItemBean ) );
             returnList.add( valueElement );
             returnList.add( valueElement );
         }
         }
         return returnList;
         return returnList;

+ 5 - 4
server/src/main/java/password/pwm/config/value/FileValue.java

@@ -29,7 +29,8 @@ import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.http.bean.ImmutableByteArray;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonProvider;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
@@ -147,7 +148,7 @@ public class FileValue extends AbstractValue implements StoredValue
                     final Optional<XmlElement> loopFileInformation = loopValueElement.getChild( XML_ELEMENT_FILE_INFORMATION );
                     final Optional<XmlElement> loopFileInformation = loopValueElement.getChild( XML_ELEMENT_FILE_INFORMATION );
                     loopFileInformation.flatMap( XmlElement::getText ).ifPresent( loopFileInformationJson ->
                     loopFileInformation.flatMap( XmlElement::getText ).ifPresent( loopFileInformationJson ->
                     {
                     {
-                        final FileInformation fileInformation = JsonUtil.deserialize( loopFileInformationJson,
+                        final FileInformation fileInformation = JsonFactory.get().deserialize( loopFileInformationJson,
                                 FileInformation.class );
                                 FileInformation.class );
 
 
                         final Optional<XmlElement> loopFileContentElement = loopValueElement.getChild( XML_ELEMENT_FILE_CONTENT );
                         final Optional<XmlElement> loopFileContentElement = loopValueElement.getChild( XML_ELEMENT_FILE_CONTENT );
@@ -188,7 +189,7 @@ public class FileValue extends AbstractValue implements StoredValue
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
 
 
             final XmlElement fileInformationElement = XmlFactory.getFactory().newElement( XML_ELEMENT_FILE_INFORMATION );
             final XmlElement fileInformationElement = XmlFactory.getFactory().newElement( XML_ELEMENT_FILE_INFORMATION );
-            fileInformationElement.addText( JsonUtil.serialize( fileInformation ) );
+            fileInformationElement.addText( JsonFactory.get().serialize( fileInformation ) );
             valueElement.addContent( fileInformationElement );
             valueElement.addContent( fileInformationElement );
 
 
             final XmlElement fileContentElement = XmlFactory.getFactory().newElement( XML_ELEMENT_FILE_CONTENT );
             final XmlElement fileContentElement = XmlFactory.getFactory().newElement( XML_ELEMENT_FILE_CONTENT );
@@ -228,7 +229,7 @@ public class FileValue extends AbstractValue implements StoredValue
     )
     )
     {
     {
         final List<Map<String, Object>> output = asMetaData();
         final List<Map<String, Object>> output = asMetaData();
-        return JsonUtil.serialize( ( Serializable ) output, JsonUtil.Flag.PrettyPrint );
+        return JsonFactory.get().serialize( ( Serializable ) output, JsonProvider.Flag.PrettyPrint );
     }
     }
 
 
     @Override
     @Override

+ 8 - 11
server/src/main/java/password/pwm/config/value/FormValue.java

@@ -20,14 +20,13 @@
 
 
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
-import com.google.gson.reflect.TypeToken;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -63,9 +62,7 @@ public class FormValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    List<FormConfiguration> srcList = JsonUtil.deserialize( input, new TypeToken<List<FormConfiguration>>()
-                    {
-                    } );
+                    List<FormConfiguration> srcList = JsonFactory.get().deserializeList( input, FormConfiguration.class );
                     srcList = srcList == null ? Collections.emptyList() : srcList;
                     srcList = srcList == null ? Collections.emptyList() : srcList;
                     while ( srcList.contains( null ) )
                     while ( srcList.contains( null ) )
                     {
                     {
@@ -94,7 +91,7 @@ public class FormValue extends AbstractValue implements StoredValue
                         }
                         }
                         else
                         else
                         {
                         {
-                            values.add( JsonUtil.deserialize( value.get(), FormConfiguration.class ) );
+                            values.add( JsonFactory.get().deserialize( value.get(), FormConfiguration.class ) );
                         }
                         }
                     }
                     }
                 }
                 }
@@ -110,7 +107,7 @@ public class FormValue extends AbstractValue implements StoredValue
         for ( final FormConfiguration value : values )
         for ( final FormConfiguration value : values )
         {
         {
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
-            valueElement.addText( JsonUtil.serialize( value ) );
+            valueElement.addText( JsonFactory.get().serialize( value ) );
             returnList.add( valueElement );
             returnList.add( valueElement );
         }
         }
         return returnList;
         return returnList;
@@ -177,16 +174,16 @@ public class FormValue extends AbstractValue implements StoredValue
                 sb.append( " Multi-Value:" ).append( formRow.isMultivalue() );
                 sb.append( " Multi-Value:" ).append( formRow.isMultivalue() );
                 sb.append( " Source:" ).append( formRow.getSource() );
                 sb.append( " Source:" ).append( formRow.getSource() );
                 sb.append( "\n" );
                 sb.append( "\n" );
-                sb.append( " Label:" ).append( JsonUtil.serializeStringMap( formRow.getLabels() ) ).append( "\n" );
-                sb.append( " Description:" ).append( JsonUtil.serializeStringMap( formRow.getDescription() ) ).append( "\n" );
+                sb.append( " Label:" ).append( JsonFactory.get().serializeStringMap( formRow.getLabels() ) ).append( "\n" );
+                sb.append( " Description:" ).append( JsonFactory.get().serializeStringMap( formRow.getDescription() ) ).append( "\n" );
                 if ( formRow.getType() == FormConfiguration.Type.select && CollectionUtil.isEmpty( formRow.getSelectOptions() ) )
                 if ( formRow.getType() == FormConfiguration.Type.select && CollectionUtil.isEmpty( formRow.getSelectOptions() ) )
                 {
                 {
-                    sb.append( " Select Options: " ).append( JsonUtil.serializeStringMap( formRow.getSelectOptions() ) ).append( "\n" );
+                    sb.append( " Select Options: " ).append( JsonFactory.get().serializeStringMap( formRow.getSelectOptions() ) ).append( "\n" );
                 }
                 }
                 if ( StringUtil.notEmpty( formRow.getRegex() ) )
                 if ( StringUtil.notEmpty( formRow.getRegex() ) )
                 {
                 {
                     sb.append( " Regex:" ).append( formRow.getRegex() )
                     sb.append( " Regex:" ).append( formRow.getRegex() )
-                            .append( " Regex Error:" ).append( JsonUtil.serializeStringMap( formRow.getRegexErrors() ) );
+                            .append( " Regex Error:" ).append( JsonFactory.get().serializeStringMap( formRow.getRegexErrors() ) );
                 }
                 }
                 if ( formRow.getType() == FormConfiguration.Type.photo )
                 if ( formRow.getType() == FormConfiguration.Type.photo )
                 {
                 {

+ 2 - 2
server/src/main/java/password/pwm/config/value/LocalizedStringArrayValue.java

@@ -25,7 +25,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -62,7 +62,7 @@ public class LocalizedStringArrayValue extends AbstractValue implements StoredVa
                 }
                 }
                 else
                 else
                 {
                 {
-                    Map<String, List<String>> srcMap = JsonUtil.deserialize( input, new TypeToken<Map<String, List<String>>>()
+                    Map<String, List<String>> srcMap = JsonFactory.get().deserialize( input, new TypeToken<Map<String, List<String>>>()
                     {
                     {
                     } );
                     } );
                     srcMap = srcMap == null ? Collections.emptyMap() : new TreeMap<>( srcMap );
                     srcMap = srcMap == null ? Collections.emptyMap() : new TreeMap<>( srcMap );

+ 2 - 5
server/src/main/java/password/pwm/config/value/LocalizedStringValue.java

@@ -20,12 +20,11 @@
 
 
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
-import com.google.gson.reflect.TypeToken;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -61,9 +60,7 @@ public class LocalizedStringValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    Map<String, String> srcMap = JsonUtil.deserialize( input, new TypeToken<Map<String, String>>()
-                    {
-                    } );
+                    Map<String, String> srcMap = JsonFactory.get().deserializeStringMap( input );
                     srcMap = srcMap == null ? Collections.emptyMap() : new TreeMap<>( srcMap );
                     srcMap = srcMap == null ? Collections.emptyMap() : new TreeMap<>( srcMap );
                     return new LocalizedStringValue( Collections.unmodifiableMap( srcMap ) );
                     return new LocalizedStringValue( Collections.unmodifiableMap( srcMap ) );
                 }
                 }

+ 2 - 5
server/src/main/java/password/pwm/config/value/NamedSecretValue.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
-import com.google.gson.reflect.TypeToken;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
@@ -31,7 +30,7 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
@@ -80,9 +79,7 @@ public class NamedSecretValue implements StoredValue
             {
             {
                 try
                 try
                 {
                 {
-                    final Map<String, NamedSecretData> values = JsonUtil.deserialize( value, new TypeToken<Map<String, NamedSecretData>>()
-                    {
-                    }.getType() );
+                    final Map<String, NamedSecretData> values = JsonFactory.get().deserializeMap( value, String.class, NamedSecretData.class );
                     final Map<String, NamedSecretData> linkedValues = new LinkedHashMap<>( values );
                     final Map<String, NamedSecretData> linkedValues = new LinkedHashMap<>( values );
                     return new NamedSecretValue( linkedValues );
                     return new NamedSecretValue( linkedValues );
                 }
                 }

+ 2 - 2
server/src/main/java/password/pwm/config/value/NumericArrayValue.java

@@ -23,7 +23,7 @@ package password.pwm.config.value;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -52,7 +52,7 @@ public class NumericArrayValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public NumericArrayValue fromJson( final String value )
             public NumericArrayValue fromJson( final String value )
             {
             {
-                final long[] longArray = JsonUtil.deserialize( value, long[].class );
+                final long[] longArray = JsonFactory.get().deserialize( value, long[].class );
                 final List<Long> list = Arrays.stream( longArray ).boxed().collect( Collectors.toList() );
                 final List<Long> list = Arrays.stream( longArray ).boxed().collect( Collectors.toList() );
                 return new NumericArrayValue( list );
                 return new NumericArrayValue( list );
             }
             }

+ 2 - 2
server/src/main/java/password/pwm/config/value/NumericValue.java

@@ -24,7 +24,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingProperty;
 import password.pwm.config.PwmSettingProperty;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -49,7 +49,7 @@ public class NumericValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public NumericValue fromJson( final String value )
             public NumericValue fromJson( final String value )
             {
             {
-                return new NumericValue( JsonUtil.deserialize( value, Long.class ) );
+                return new NumericValue( JsonFactory.get().deserialize( value, Long.class ) );
             }
             }
 
 
             @Override
             @Override

+ 4 - 7
server/src/main/java/password/pwm/config/value/OptionListValue.java

@@ -20,11 +20,10 @@
 
 
 package password.pwm.config.value;
 package password.pwm.config.value;
 
 
-import com.google.gson.reflect.TypeToken;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -59,15 +58,13 @@ public class OptionListValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    Set<String> srcList = JsonUtil.deserialize( input, new TypeToken<Set<String>>()
-                    {
-                    } );
-                    srcList = srcList == null ? Collections.emptySet() : srcList;
+                    List<String> srcList = JsonFactory.get().deserializeStringList( input );
+                    srcList = srcList == null ? Collections.emptyList() : srcList;
                     while ( srcList.contains( null ) )
                     while ( srcList.contains( null ) )
                     {
                     {
                         srcList.remove( null );
                         srcList.remove( null );
                     }
                     }
-                    return new OptionListValue( Collections.unmodifiableSet( srcList ) );
+                    return new OptionListValue( Set.copyOf( srcList ) );
                 }
                 }
             }
             }
 
 

+ 2 - 2
server/src/main/java/password/pwm/config/value/PasswordValue.java

@@ -30,7 +30,7 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.LazySupplier;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -67,7 +67,7 @@ public class PasswordValue implements StoredValue
             @Override
             @Override
             public PasswordValue fromJson( final String value )
             public PasswordValue fromJson( final String value )
             {
             {
-                final String strValue = JsonUtil.deserialize( value, String.class );
+                final String strValue = JsonFactory.get().deserialize( value, String.class );
                 if ( strValue != null && !strValue.isEmpty() )
                 if ( strValue != null && !strValue.isEmpty() )
                 {
                 {
                     try
                     try

+ 3 - 3
server/src/main/java/password/pwm/config/value/PrivateKeyValue.java

@@ -25,7 +25,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -212,8 +212,8 @@ public class PrivateKeyValue extends AbstractValue
     {
     {
         if ( privateKeyCertificate != null )
         if ( privateKeyCertificate != null )
         {
         {
-            return "PrivateKeyCertificate: key=" + JsonUtil.serializeMap( X509Utils.makeDebugInfoMap( privateKeyCertificate.getKey() ) )
-                    + ", certificates=" + JsonUtil.serializeCollection( X509Utils.makeDebugInfoMap( privateKeyCertificate.getCertificates() ) );
+            return "PrivateKeyCertificate: key=" + JsonFactory.get().serializeMap( X509Utils.makeDebugInfoMap( privateKeyCertificate.getKey() ) )
+                    + ", certificates=" + JsonFactory.get().serializeCollection( X509Utils.makeDebugInfoMap( privateKeyCertificate.getCertificates() ) );
         }
         }
         return "";
         return "";
     }
     }

+ 7 - 12
server/src/main/java/password/pwm/config/value/RemoteWebServiceValue.java

@@ -27,7 +27,7 @@ import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.RemoteWebServiceConfiguration;
 import password.pwm.config.value.data.RemoteWebServiceConfiguration;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -71,12 +71,7 @@ public class RemoteWebServiceValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    List<RemoteWebServiceConfiguration> srcList = JsonUtil.deserialize( input,
-                            new TypeToken<List<RemoteWebServiceConfiguration>>()
-                            {
-                            }
-                    );
-
+                    List<RemoteWebServiceConfiguration> srcList = JsonFactory.get().deserializeList( input, RemoteWebServiceConfiguration.class );
                     srcList = srcList == null ? new ArrayList<>() : srcList;
                     srcList = srcList == null ? new ArrayList<>() : srcList;
                     srcList.removeIf( Objects::isNull );
                     srcList.removeIf( Objects::isNull );
                     return new RemoteWebServiceValue( Collections.unmodifiableList( srcList ) );
                     return new RemoteWebServiceValue( Collections.unmodifiableList( srcList ) );
@@ -98,7 +93,7 @@ public class RemoteWebServiceValue extends AbstractValue implements StoredValue
                     final Optional<String> value = loopValueElement.getText();
                     final Optional<String> value = loopValueElement.getText();
                     if ( value.isPresent() )
                     if ( value.isPresent() )
                     {
                     {
-                        final RemoteWebServiceConfiguration parsedValue = JsonUtil.deserialize( value.get(), RemoteWebServiceConfiguration.class );
+                        final RemoteWebServiceConfiguration parsedValue = JsonFactory.get().deserialize( value.get(), RemoteWebServiceConfiguration.class );
                         final Optional<String> decodedValue = StoredValueEncoder.decode(
                         final Optional<String> decodedValue = StoredValueEncoder.decode(
                                 parsedValue.getPassword(),
                                 parsedValue.getPassword(),
                                 StoredValueEncoder.Mode.ENCODED,
                                 StoredValueEncoder.Mode.ENCODED,
@@ -134,7 +129,7 @@ public class RemoteWebServiceValue extends AbstractValue implements StoredValue
             }
             }
 
 
             final RemoteWebServiceConfiguration clonedValue = value.toBuilder().password( encodedValue ).build();
             final RemoteWebServiceConfiguration clonedValue = value.toBuilder().password( encodedValue ).build();
-            valueElement.addText( JsonUtil.serialize( clonedValue ) );
+            valueElement.addText( JsonFactory.get().serialize( clonedValue ) );
             returnList.add( valueElement );
             returnList.add( valueElement );
         }
         }
         return returnList;
         return returnList;
@@ -173,8 +168,8 @@ public class RemoteWebServiceValue extends AbstractValue implements StoredValue
 
 
     public List<Map<String, Object>> toInfoMap( )
     public List<Map<String, Object>> toInfoMap( )
     {
     {
-        final String originalJson = JsonUtil.serializeCollection( values );
-        final List<Map<String, Object>> tempObj = JsonUtil.deserialize( originalJson, new TypeToken<List<Map<String, Object>>>()
+        final String originalJson = JsonFactory.get().serializeCollection( values );
+        final List<Map<String, Object>> tempObj = JsonFactory.get().deserialize( originalJson, new TypeToken<List<Map<String, Object>>>()
         {
         {
         } );
         } );
         for ( final Map<String, Object> mapObj : tempObj )
         for ( final Map<String, Object> mapObj : tempObj )
@@ -236,7 +231,7 @@ public class RemoteWebServiceValue extends AbstractValue implements StoredValue
     @Override
     @Override
     public String toDebugString( final Locale locale )
     public String toDebugString( final Locale locale )
     {
     {
-        return JsonUtil.serializeCollection( this.makeDebugJsonObject( locale ) );
+        return JsonFactory.get().serializeCollection( this.makeDebugJsonObject( locale ) );
     }
     }
 
 
 }
 }

+ 3 - 3
server/src/main/java/password/pwm/config/value/StoredValueEncoder.java

@@ -25,7 +25,7 @@ import password.pwm.PwmConstants;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmOperationalException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmBlockAlgorithm;
 import password.pwm.util.secure.PwmBlockAlgorithm;
@@ -221,7 +221,7 @@ public abstract class StoredValueEncoder
                 {
                 {
                     final String salt = PwmRandom.getInstance().alphaNumericString( 32 );
                     final String salt = PwmRandom.getInstance().alphaNumericString( 32 );
                     final StoredPwData storedPwData = new StoredPwData( salt, rawValue );
                     final StoredPwData storedPwData = new StoredPwData( salt, rawValue );
-                    final String jsonData = JsonUtil.serialize( storedPwData );
+                    final String jsonData = JsonFactory.get().serialize( storedPwData );
                     final String encryptedValue = SecureEngine.encryptToString( jsonData, pwmSecurityKey, PwmBlockAlgorithm.CONFIG );
                     final String encryptedValue = SecureEngine.encryptToString( jsonData, pwmSecurityKey, PwmBlockAlgorithm.CONFIG );
                     return Mode.ENCODED.getPrefix() + encryptedValue;
                     return Mode.ENCODED.getPrefix() + encryptedValue;
                 }
                 }
@@ -243,7 +243,7 @@ public abstract class StoredValueEncoder
             {
             {
                 final String pwValueSuffix = input.getValue( );
                 final String pwValueSuffix = input.getValue( );
                 final String decryptedValue = SecureEngine.decryptStringValue( pwValueSuffix, pwmSecurityKey, PwmBlockAlgorithm.CONFIG );
                 final String decryptedValue = SecureEngine.decryptStringValue( pwValueSuffix, pwmSecurityKey, PwmBlockAlgorithm.CONFIG );
-                final StoredPwData storedPwData = JsonUtil.deserialize( decryptedValue, StoredPwData.class );
+                final StoredPwData storedPwData = JsonFactory.get().deserialize( decryptedValue, StoredPwData.class );
                 return storedPwData.getValue();
                 return storedPwData.getValue();
             }
             }
             catch ( final Exception e )
             catch ( final Exception e )

+ 2 - 2
server/src/main/java/password/pwm/config/value/StringArrayValue.java

@@ -24,7 +24,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.PwmSettingFlag;
 import password.pwm.config.PwmSettingFlag;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -64,7 +64,7 @@ public class StringArrayValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    return new StringArrayValue( JsonUtil.deserializeStringList( input ) );
+                    return new StringArrayValue( JsonFactory.get().deserializeStringList( input ) );
                 }
                 }
             }
             }
 
 

+ 2 - 2
server/src/main/java/password/pwm/config/value/StringValue.java

@@ -28,7 +28,7 @@ import password.pwm.config.PwmSettingSyntax;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.StoredConfigXmlConstants;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.stored.XmlOutputProcessData;
 import password.pwm.config.value.data.FormConfiguration;
 import password.pwm.config.value.data.FormConfiguration;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
@@ -61,7 +61,7 @@ public class StringValue extends AbstractValue implements StoredValue
             @Override
             @Override
             public StringValue fromJson( final String input )
             public StringValue fromJson( final String input )
             {
             {
-                final String newValue = JsonUtil.deserialize( input, String.class );
+                final String newValue = JsonFactory.get().deserialize( input, String.class );
                 return new StringValue( newValue );
                 return new StringValue( newValue );
             }
             }
 
 

+ 4 - 4
server/src/main/java/password/pwm/config/value/UserPermissionValue.java

@@ -28,7 +28,7 @@ import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.ldap.permission.UserPermissionType;
 import password.pwm.ldap.permission.UserPermissionType;
 import password.pwm.ldap.permission.UserPermissionUtility;
 import password.pwm.ldap.permission.UserPermissionUtility;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -81,7 +81,7 @@ public class UserPermissionValue extends AbstractValue implements StoredValue
                 }
                 }
                 else
                 else
                 {
                 {
-                    List<UserPermission> srcList = JsonUtil.deserializeList( input, UserPermission.class );
+                    List<UserPermission> srcList = JsonFactory.get().deserializeList( input, UserPermission.class );
                     srcList = srcList == null ? Collections.emptyList() : srcList;
                     srcList = srcList == null ? Collections.emptyList() : srcList;
                     return new UserPermissionValue( Collections.unmodifiableList( srcList ) );
                     return new UserPermissionValue( Collections.unmodifiableList( srcList ) );
                 }
                 }
@@ -103,7 +103,7 @@ public class UserPermissionValue extends AbstractValue implements StoredValue
                     {
                     {
                         if ( newType )
                         if ( newType )
                         {
                         {
-                            final UserPermission userPermission = JsonUtil.deserialize( value.get(), UserPermission.class );
+                            final UserPermission userPermission = JsonFactory.get().deserialize( value.get(), UserPermission.class );
                             values.add( userPermission );
                             values.add( userPermission );
                         }
                         }
                         else
                         else
@@ -129,7 +129,7 @@ public class UserPermissionValue extends AbstractValue implements StoredValue
         for ( final UserPermission value : values )
         for ( final UserPermission value : values )
         {
         {
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
             final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
-            valueElement.addText( JsonUtil.serialize( value ) );
+            valueElement.addText( JsonFactory.get().serialize( value ) );
             returnList.add( valueElement );
             returnList.add( valueElement );
         }
         }
         return returnList;
         return returnList;

+ 6 - 6
server/src/main/java/password/pwm/config/value/VerificationMethodValue.java

@@ -29,7 +29,7 @@ import password.pwm.error.PwmOperationalException;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlElement;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.java.XmlFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -133,7 +133,7 @@ public class VerificationMethodValue extends AbstractValue implements StoredValu
                 }
                 }
                 else
                 else
                 {
                 {
-                    final VerificationMethodSettings settings = JsonUtil.deserialize( input, VerificationMethodSettings.class );
+                    final VerificationMethodSettings settings = JsonFactory.get().deserialize( input, VerificationMethodSettings.class );
                     return new VerificationMethodValue( settings );
                     return new VerificationMethodValue( settings );
                 }
                 }
             }
             }
@@ -148,7 +148,7 @@ public class VerificationMethodValue extends AbstractValue implements StoredValu
                     final Optional<String> inputStr = valueElement.get().getText();
                     final Optional<String> inputStr = valueElement.get().getText();
                     if ( inputStr.isPresent() )
                     if ( inputStr.isPresent() )
                     {
                     {
-                        final VerificationMethodSettings settings = JsonUtil.deserialize( inputStr.get(), VerificationMethodSettings.class );
+                        final VerificationMethodSettings settings = JsonFactory.get().deserialize( inputStr.get(), VerificationMethodSettings.class );
                         return new VerificationMethodValue( settings );
                         return new VerificationMethodValue( settings );
                     }
                     }
                 }
                 }
@@ -161,7 +161,7 @@ public class VerificationMethodValue extends AbstractValue implements StoredValu
     public List<XmlElement> toXmlValues( final String valueElementName, final XmlOutputProcessData xmlOutputProcessData )
     public List<XmlElement> toXmlValues( final String valueElementName, final XmlOutputProcessData xmlOutputProcessData )
     {
     {
         final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
         final XmlElement valueElement = XmlFactory.getFactory().newElement( valueElementName );
-        valueElement.addText( JsonUtil.serialize( value ) );
+        valueElement.addText( JsonFactory.get().serialize( value ) );
         return Collections.singletonList( valueElement );
         return Collections.singletonList( valueElement );
     }
     }
 
 
@@ -208,11 +208,11 @@ public class VerificationMethodValue extends AbstractValue implements StoredValu
 
 
         out.append( "optional methods: " ).append( optionals.isEmpty()
         out.append( "optional methods: " ).append( optionals.isEmpty()
                 ? LocaleHelper.getLocalizedMessage( locale, Display.Value_NotApplicable, null )
                 ? LocaleHelper.getLocalizedMessage( locale, Display.Value_NotApplicable, null )
-                : JsonUtil.serializeCollection( optionals )
+                : JsonFactory.get().serializeCollection( optionals )
         );
         );
         out.append( ", required methods: " ).append( required.isEmpty()
         out.append( ", required methods: " ).append( required.isEmpty()
                 ? LocaleHelper.getLocalizedMessage( locale, Display.Value_NotApplicable, null )
                 ? LocaleHelper.getLocalizedMessage( locale, Display.Value_NotApplicable, null )
-                : JsonUtil.serializeCollection( required )
+                : JsonFactory.get().serializeCollection( required )
         );
         );
 
 
         if ( value.getMinOptionalRequired() > 0 )
         if ( value.getMinOptionalRequired() > 0 )

+ 8 - 8
server/src/main/java/password/pwm/config/value/data/ActionConfiguration.java

@@ -37,6 +37,14 @@ import java.util.Map;
 @Builder( toBuilder = true )
 @Builder( toBuilder = true )
 public class ActionConfiguration implements Serializable
 public class ActionConfiguration implements Serializable
 {
 {
+    private String name;
+    private String description;
+
+    @Builder.Default
+    private List<ActionConfiguration.WebAction> webActions = Collections.emptyList();
+
+    @Builder.Default
+    private List<ActionConfiguration.LdapAction> ldapActions = Collections.emptyList();
 
 
     public enum WebMethod
     public enum WebMethod
     {
     {
@@ -91,14 +99,6 @@ public class ActionConfiguration implements Serializable
         private String attributeValue = "";
         private String attributeValue = "";
     }
     }
 
 
-    private String name;
-    private String description;
-
-    @Builder.Default
-    private List<ActionConfiguration.WebAction> webActions = Collections.emptyList();
-
-    @Builder.Default
-    private List<ActionConfiguration.LdapAction> ldapActions = Collections.emptyList();
 
 
     public void validate( ) throws PwmOperationalException
     public void validate( ) throws PwmOperationalException
     {
     {

+ 2 - 2
server/src/main/java/password/pwm/config/value/data/CustomLinkConfiguration.java

@@ -23,7 +23,7 @@ package password.pwm.config.value.data;
 import lombok.EqualsAndHashCode;
 import lombok.EqualsAndHashCode;
 import lombok.Value;
 import lombok.Value;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.Collections;
 import java.util.Collections;
@@ -66,7 +66,7 @@ public class CustomLinkConfiguration implements Serializable
         final StringBuilder sb = new StringBuilder();
         final StringBuilder sb = new StringBuilder();
 
 
         sb.append( "CustomLink: " );
         sb.append( "CustomLink: " );
-        sb.append( JsonUtil.serialize( this ) );
+        sb.append( JsonFactory.get().serialize( this ) );
 
 
         return sb.toString();
         return sb.toString();
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/health/ApplianceStatusChecker.java

@@ -33,7 +33,7 @@ import password.pwm.svc.httpclient.PwmHttpClient;
 import password.pwm.svc.httpclient.PwmHttpClientConfiguration;
 import password.pwm.svc.httpclient.PwmHttpClientConfiguration;
 import password.pwm.svc.httpclient.PwmHttpClientRequest;
 import password.pwm.svc.httpclient.PwmHttpClientRequest;
 import password.pwm.svc.httpclient.PwmHttpClientResponse;
 import password.pwm.svc.httpclient.PwmHttpClientResponse;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -114,7 +114,7 @@ public class ApplianceStatusChecker implements HealthSupplier
 
 
         LOGGER.debug( () -> "response from /sspr/appliance-update-status: " + jsonString );
         LOGGER.debug( () -> "response from /sspr/appliance-update-status: " + jsonString );
 
 
-        final UpdateStatus updateStatus = JsonUtil.deserialize( jsonString, UpdateStatus.class );
+        final UpdateStatus updateStatus = JsonFactory.get().deserialize( jsonString, UpdateStatus.class );
 
 
         if ( updateStatus.pendingInstallation )
         if ( updateStatus.pendingInstallation )
         {
         {

+ 1 - 1
server/src/main/java/password/pwm/http/HttpHeader.java

@@ -90,6 +90,6 @@ public enum HttpHeader
 
 
     public static Optional<HttpHeader> forHttpHeader( final String header )
     public static Optional<HttpHeader> forHttpHeader( final String header )
     {
     {
-        return JavaHelper.readEnumFromPredicate( HttpHeader.class, loopHeader -> header.equalsIgnoreCase( loopHeader.getHttpName() ) );
+        return JavaHelper.readEnumFromCaseIgnoreString( HttpHeader.class, header );
     }
     }
 }
 }

+ 4 - 8
server/src/main/java/password/pwm/http/HttpMethod.java

@@ -20,6 +20,8 @@
 
 
 package password.pwm.http;
 package password.pwm.http;
 
 
+import password.pwm.util.java.JavaHelper;
+
 import java.util.Optional;
 import java.util.Optional;
 
 
 public enum HttpMethod
 public enum HttpMethod
@@ -42,14 +44,8 @@ public enum HttpMethod
 
 
     public static Optional<HttpMethod> fromString( final String input )
     public static Optional<HttpMethod> fromString( final String input )
     {
     {
-        for ( final HttpMethod method : HttpMethod.values() )
-        {
-            if ( method.toString().equalsIgnoreCase( input ) )
-            {
-                return Optional.of( method );
-            }
-        }
-        return Optional.empty();
+        return JavaHelper.readEnumFromPredicate( HttpMethod.class,
+                httpMethod -> httpMethod.toString().equalsIgnoreCase( input ) );
     }
     }
 
 
     public boolean isIdempotent( )
     public boolean isIdempotent( )

+ 4 - 4
server/src/main/java/password/pwm/http/PwmHttpRequestWrapper.java

@@ -32,7 +32,7 @@ import password.pwm.util.ServletUtility;
 import password.pwm.util.Validator;
 import password.pwm.util.Validator;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.Cookie;
@@ -112,7 +112,7 @@ public class PwmHttpRequestWrapper
     {
     {
         final boolean bypassInputValidation = flags != null && Arrays.asList( flags ).contains( Flag.BypassValidation );
         final boolean bypassInputValidation = flags != null && Arrays.asList( flags ).contains( Flag.BypassValidation );
         final String bodyString = readRequestBodyAsString();
         final String bodyString = readRequestBodyAsString();
-        final Map<String, String> inputMap = JsonUtil.deserializeStringMap( bodyString );
+        final Map<String, String> inputMap = JsonFactory.get().deserializeStringMap( bodyString );
 
 
         final boolean trim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_TRIM ) );
         final boolean trim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_TRIM ) );
         final boolean passwordTrim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_PASSWORD_TRIM ) );
         final boolean passwordTrim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_PASSWORD_TRIM ) );
@@ -148,7 +148,7 @@ public class PwmHttpRequestWrapper
     {
     {
         final boolean bypassInputValidation = flags != null && Arrays.asList( flags ).contains( Flag.BypassValidation );
         final boolean bypassInputValidation = flags != null && Arrays.asList( flags ).contains( Flag.BypassValidation );
         final String bodyString = readRequestBodyAsString();
         final String bodyString = readRequestBodyAsString();
-        final Map<String, Object> inputMap = JsonUtil.deserializeMap( bodyString );
+        final Map<String, Object> inputMap = JsonFactory.get().deserializeMap( bodyString );
 
 
         final boolean trim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_TRIM ) );
         final boolean trim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_TRIM ) );
         final boolean passwordTrim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_PASSWORD_TRIM ) );
         final boolean passwordTrim = Boolean.parseBoolean( appConfig.readAppProperty( AppProperty.SECURITY_INPUT_PASSWORD_TRIM ) );
@@ -538,7 +538,7 @@ public class PwmHttpRequestWrapper
         final String json = readRequestBodyAsString();
         final String json = readRequestBodyAsString();
         try
         try
         {
         {
-            return JsonUtil.deserialize( json, classOfT );
+            return JsonFactory.get().deserialize( json, classOfT );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
         {
         {

+ 2 - 2
server/src/main/java/password/pwm/http/PwmResponse.java

@@ -34,7 +34,7 @@ import password.pwm.http.servlet.command.CommandServlet;
 import password.pwm.i18n.Message;
 import password.pwm.i18n.Message;
 import password.pwm.util.Validator;
 import password.pwm.util.Validator;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.PwmSecurityKey;
@@ -241,7 +241,7 @@ public class PwmResponse extends PwmHttpResponseWrapper
     public void writeEncryptedCookie( final String cookieName, final Serializable cookieValue, final int seconds, final PwmCookiePath path )
     public void writeEncryptedCookie( final String cookieName, final Serializable cookieValue, final int seconds, final PwmCookiePath path )
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
-        final String jsonValue = JsonUtil.serialize( cookieValue );
+        final String jsonValue = JsonFactory.get().serialize( cookieValue );
         final PwmSecurityKey pwmSecurityKey = pwmRequest.getPwmSession().getSecurityKey( pwmRequest );
         final PwmSecurityKey pwmSecurityKey = pwmRequest.getPwmSession().getSecurityKey( pwmRequest );
         final String encryptedValue = pwmRequest.getPwmDomain().getSecureService().encryptToString( jsonValue, pwmSecurityKey );
         final String encryptedValue = pwmRequest.getPwmDomain().getSecureService().encryptToString( jsonValue, pwmSecurityKey );
         writeCookie( cookieName, encryptedValue, seconds, path, PwmHttpResponseWrapper.Flag.BypassSanitation );
         writeCookie( cookieName, encryptedValue, seconds, path, PwmHttpResponseWrapper.Flag.BypassSanitation );

+ 2 - 2
server/src/main/java/password/pwm/http/PwmSession.java

@@ -42,7 +42,7 @@ import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.secure.PwmRandom;
@@ -322,7 +322,7 @@ public class PwmSession implements Serializable
             return "exception generating PwmSession.toString(): " + e.getMessage();
             return "exception generating PwmSession.toString(): " + e.getMessage();
         }
         }
 
 
-        return "PwmSession instance: " + JsonUtil.serializeMap( debugData );
+        return "PwmSession instance: " + JsonFactory.get().serializeMap( debugData );
     }
     }
 
 
     public boolean setLocale( final PwmRequest pwmRequest, final String localeString )
     public boolean setLocale( final PwmRequest pwmRequest, final String localeString )

+ 20 - 23
server/src/main/java/password/pwm/http/servlet/ClientApiServlet.java

@@ -71,6 +71,7 @@ import java.time.Instant;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
@@ -80,6 +81,7 @@ import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 
 @WebServlet(
 @WebServlet(
         name = "ClientApiServlet",
         name = "ClientApiServlet",
@@ -180,7 +182,7 @@ public class ClientApiServlet extends ControlledPwmServlet
                 pwmRequest.getPwmResponse().getHttpServletResponse(),
                 pwmRequest.getPwmResponse().getHttpServletResponse(),
                 pageUrl
                 pageUrl
         );
         );
-        final RestResultBean restResultBean = RestResultBean.withData( appData );
+        final RestResultBean<AppData> restResultBean = RestResultBean.withData( appData, AppData.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -188,7 +190,7 @@ public class ClientApiServlet extends ControlledPwmServlet
     @ActionHandler( action = "strings" )
     @ActionHandler( action = "strings" )
     public ProcessStatus doGetStringsData( final PwmRequest pwmRequest
     public ProcessStatus doGetStringsData( final PwmRequest pwmRequest
     )
     )
-            throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException
+            throws PwmUnrecoverableException, IOException, ServletException
     {
     {
         final String bundleName = pwmRequest.readParameterAsString( "bundle" );
         final String bundleName = pwmRequest.readParameterAsString( "bundle" );
         final int maxCacheAgeSeconds = 60 * 5;
         final int maxCacheAgeSeconds = 60 * 5;
@@ -201,9 +203,9 @@ public class ClientApiServlet extends ControlledPwmServlet
 
 
         try
         try
         {
         {
-            final LinkedHashMap<String, String> displayData = new LinkedHashMap<>( makeDisplayData( pwmRequest.getPwmDomain(),
+            final Map<String, String> displayData = new LinkedHashMap<>( makeDisplayData( pwmRequest.getPwmDomain(),
                     pwmRequest, bundleName ) );
                     pwmRequest, bundleName ) );
-            final RestResultBean restResultBean = RestResultBean.withData( displayData );
+            final RestResultBean<Map> restResultBean = RestResultBean.withData( displayData, Map.class );
             pwmRequest.outputJsonResult( restResultBean );
             pwmRequest.outputJsonResult( restResultBean );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
@@ -227,7 +229,7 @@ public class ClientApiServlet extends ControlledPwmServlet
             final PublicHealthData jsonOutput = RestHealthServer.processGetHealthCheckData(
             final PublicHealthData jsonOutput = RestHealthServer.processGetHealthCheckData(
                     pwmRequest.getPwmDomain(),
                     pwmRequest.getPwmDomain(),
                     pwmRequest.getLocale() );
                     pwmRequest.getLocale() );
-            final RestResultBean restResultBean = RestResultBean.withData( jsonOutput );
+            final RestResultBean restResultBean = RestResultBean.withData( jsonOutput, PublicHealthData.class );
             pwmRequest.outputJsonResult( restResultBean );
             pwmRequest.outputJsonResult( restResultBean );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
@@ -247,7 +249,7 @@ public class ClientApiServlet extends ControlledPwmServlet
         final PingResponse pingResponse = new PingResponse();
         final PingResponse pingResponse = new PingResponse();
         pingResponse.setTime( Instant.now() );
         pingResponse.setTime( Instant.now() );
         pingResponse.setRuntimeNonce( pwmRequest.getPwmApplication().getRuntimeNonce() );
         pingResponse.setRuntimeNonce( pwmRequest.getPwmApplication().getRuntimeNonce() );
-        pwmRequest.outputJsonResult( RestResultBean.withData( pingResponse ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( pingResponse, PingResponse.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -383,23 +385,16 @@ public class ClientApiServlet extends ControlledPwmServlet
             }
             }
         }
         }
 
 
-        {
-            final List<String> epsTypes = new ArrayList<>();
-            for ( final EpsStatistic loopEpsType : EpsStatistic.values() )
-            {
-                epsTypes.add( loopEpsType.toString() );
-            }
-            settingMap.put( "epsTypes", epsTypes );
-        }
+        settingMap.put( "epsTypes", EnumSet.allOf( EpsStatistic.class )
+                .stream()
+                .map( EpsStatistic::toString )
+                .collect( Collectors.toList() ) );
+
+        settingMap.put( "epsDurations", EnumSet.allOf( Statistic.EpsDuration.class )
+                .stream()
+                .map( Statistic.EpsDuration::toString )
+                .collect( Collectors.toList() ) );
 
 
-        {
-            final List<String> epsDurations = new ArrayList<>();
-            for ( final Statistic.EpsDuration loopEpsDuration : Statistic.EpsDuration.values() )
-            {
-                epsDurations.add( loopEpsDuration.toString() );
-            }
-            settingMap.put( "epsDurations", epsDurations );
-        }
 
 
         {
         {
             final Map<String, String> localeInfo = new LinkedHashMap<>();
             final Map<String, String> localeInfo = new LinkedHashMap<>();
@@ -491,7 +486,9 @@ public class ClientApiServlet extends ControlledPwmServlet
             jsonOutput.keyData = RestStatisticsServer.OutputVersion1.doKeyStat( statisticsManager, statKey );
             jsonOutput.keyData = RestStatisticsServer.OutputVersion1.doKeyStat( statisticsManager, statKey );
         }
         }
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( jsonOutput );
+        final RestResultBean<RestStatisticsServer.OutputVersion1.JsonOutput> restResultBean = RestResultBean.withData(
+                jsonOutput,
+                RestStatisticsServer.OutputVersion1.JsonOutput.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/LoginServlet.java

@@ -180,7 +180,7 @@ public class LoginServlet extends ControlledPwmServlet
         // login has succeeded
         // login has succeeded
         final String nextLoginUrl = determinePostLoginUrl( pwmRequest );
         final String nextLoginUrl = determinePostLoginUrl( pwmRequest );
         final HashMap<String, String> resultMap = new HashMap<>( Collections.singletonMap( "nextURL", nextLoginUrl ) );
         final HashMap<String, String> resultMap = new HashMap<>( Collections.singletonMap( "nextURL", nextLoginUrl ) );
-        final RestResultBean restResultBean = RestResultBean.withData( resultMap );
+        final RestResultBean<Map> restResultBean = RestResultBean.withData( resultMap, Map.class );
         LOGGER.debug( pwmRequest, () -> "rest login succeeded" );
         LOGGER.debug( pwmRequest, () -> "rest login succeeded" );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;

+ 6 - 6
server/src/main/java/password/pwm/http/servlet/SetupOtpServlet.java

@@ -54,7 +54,7 @@ import password.pwm.svc.otp.OtpService;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.Validator;
 import password.pwm.util.Validator;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.ws.server.RestResultBean;
 import password.pwm.ws.server.RestResultBean;
@@ -287,7 +287,7 @@ public class SetupOtpServlet extends ControlledPwmServlet
         final OtpService otpService = pwmDomain.getOtpService();
         final OtpService otpService = pwmDomain.getOtpService();
 
 
         final String bodyString = pwmRequest.readRequestBodyAsString();
         final String bodyString = pwmRequest.readRequestBodyAsString();
-        final Map<String, String> clientValues = JsonUtil.deserializeStringMap( bodyString );
+        final Map<String, String> clientValues = JsonFactory.get().deserializeStringMap( bodyString );
         final String code = Validator.sanitizeInputValue( pwmRequest.getAppConfig(), clientValues.get( "code" ), 1024 );
         final String code = Validator.sanitizeInputValue( pwmRequest.getAppConfig(), clientValues.get( "code" ), 1024 );
 
 
         try
         try
@@ -299,9 +299,9 @@ public class SetupOtpServlet extends ControlledPwmServlet
                     code,
                     code,
                     false
                     false
             );
             );
-            final RestResultBean restResultBean = RestResultBean.withData( passed );
+            final RestResultBean restResultBean = RestResultBean.withData( passed, Boolean.class );
 
 
-            LOGGER.trace( pwmRequest, () -> "returning result for restValidateCode: " + JsonUtil.serialize( restResultBean ) );
+            LOGGER.trace( pwmRequest, () -> "returning result for restValidateCode: " + JsonFactory.get().serialize( restResultBean ) );
             pwmRequest.outputJsonResult( restResultBean );
             pwmRequest.outputJsonResult( restResultBean );
         }
         }
         catch ( final PwmOperationalException e )
         catch ( final PwmOperationalException e )
@@ -362,7 +362,7 @@ public class SetupOtpServlet extends ControlledPwmServlet
             {
             {
                 if ( pwmRequest.getAppConfig().isDevDebugMode() )
                 if ( pwmRequest.getAppConfig().isDevDebugMode() )
                 {
                 {
-                    LOGGER.trace( pwmRequest, () -> "testing against otp record: " + JsonUtil.serialize( otpBean.getOtpUserRecord() ) );
+                    LOGGER.trace( pwmRequest, () -> "testing against otp record: " + JsonFactory.get().serialize( otpBean.getOtpUserRecord() ) );
                 }
                 }
 
 
                 if ( otpService.validateToken(
                 if ( otpService.validateToken(
@@ -454,7 +454,7 @@ public class SetupOtpServlet extends ControlledPwmServlet
                 LOGGER.trace( pwmRequest, () -> "generated new otp record" );
                 LOGGER.trace( pwmRequest, () -> "generated new otp record" );
                 if ( config.getAppConfig().isDevDebugMode() )
                 if ( config.getAppConfig().isDevDebugMode() )
                 {
                 {
-                    LOGGER.trace( pwmRequest, () -> "newly generated otp record: " + JsonUtil.serialize( otpUserRecord ) );
+                    LOGGER.trace( pwmRequest, () -> "newly generated otp record: " + JsonFactory.get().serialize( otpUserRecord ) );
                 }
                 }
             }
             }
             catch ( final Exception e )
             catch ( final Exception e )

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/accountinfo/AccountInformationServlet.java

@@ -114,7 +114,7 @@ public class AccountInformationServlet extends ControlledPwmServlet
                 pwmRequest.getPwmSession().getUserInfo(),
                 pwmRequest.getPwmSession().getUserInfo(),
                 pwmRequest.getLocale()
                 pwmRequest.getLocale()
         );
         );
-        pwmRequest.outputJsonResult( RestResultBean.withData( accountInformationBean ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( accountInformationBean, AccountInformationBean.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 

+ 18 - 15
server/src/main/java/password/pwm/http/servlet/admin/AdminServlet.java

@@ -63,7 +63,8 @@ import password.pwm.svc.stats.StatisticsService;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.ClosableIterator;
 import password.pwm.util.java.ClosableIterator;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonProvider;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.LocalDBLogger;
 import password.pwm.util.logging.LocalDBLogger;
@@ -377,11 +378,11 @@ public class AdminServlet extends ControlledPwmServlet
     private ProcessStatus processReportStatus( final PwmRequest pwmRequest )
     private ProcessStatus processReportStatus( final PwmRequest pwmRequest )
             throws IOException
             throws IOException
     {
     {
-        final ReportStatusBean returnMap = ReportStatusBean.makeReportStatusData(
+        final ReportStatusBean reportStatusBean = ReportStatusBean.makeReportStatusData(
                 pwmRequest.getPwmApplication().getReportService(),
                 pwmRequest.getPwmApplication().getReportService(),
                 pwmRequest.getPwmSession().getSessionStateBean().getLocale()
                 pwmRequest.getPwmSession().getSessionStateBean().getLocale()
         );
         );
-        final RestResultBean restResultBean = RestResultBean.withData( returnMap );
+        final RestResultBean restResultBean = RestResultBean.withData( reportStatusBean, ReportStatusBean.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -397,7 +398,7 @@ public class AdminServlet extends ControlledPwmServlet
                 pwmRequest.getPwmSession().getSessionStateBean().getLocale()
                 pwmRequest.getPwmSession().getSessionStateBean().getLocale()
         ) );
         ) );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( returnMap );
+        final RestResultBean restResultBean = RestResultBean.withData( returnMap, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -423,10 +424,10 @@ public class AdminServlet extends ControlledPwmServlet
             }
             }
         }
         }
 
 
-        final HashMap<String, Object> returnData = new HashMap<>();
+        final Map<String, Object> returnData = new HashMap<>();
         returnData.put( "users", reportData );
         returnData.put( "users", reportData );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( returnData );
+        final RestResultBean restResultBean = RestResultBean.withData( returnData, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -451,7 +452,7 @@ public class AdminServlet extends ControlledPwmServlet
                     pwmRequest.getLabel(),
                     pwmRequest.getLabel(),
                     userIdentity
                     userIdentity
             );
             );
-            final String output = JsonUtil.serialize( userDebugData, JsonUtil.Flag.PrettyPrint );
+            final String output = JsonFactory.get().serialize( userDebugData, JsonProvider.Flag.PrettyPrint );
             pwmRequest.getPwmResponse().getOutputStream().write( output.getBytes( PwmConstants.DEFAULT_CHARSET ) );
             pwmRequest.getPwmResponse().getOutputStream().write( output.getBytes( PwmConstants.DEFAULT_CHARSET ) );
         }
         }
         else
         else
@@ -488,7 +489,7 @@ public class AdminServlet extends ControlledPwmServlet
 
 
         final HashMap<String, Object> resultData = new HashMap<>( Collections.singletonMap( "records", records ) );
         final HashMap<String, Object> resultData = new HashMap<>( Collections.singletonMap( "records", records ) );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( resultData );
+        final RestResultBean restResultBean = RestResultBean.withData( resultData, Map.class );
         LOGGER.debug( pwmRequest, () -> "output " + records.size() + " audit records." );
         LOGGER.debug( pwmRequest, () -> "output " + records.size() + " audit records." );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -500,7 +501,7 @@ public class AdminServlet extends ControlledPwmServlet
     {
     {
         final int max = readMaxParameter( pwmRequest, 1000, 10 * 1000 );
         final int max = readMaxParameter( pwmRequest, 1000, 10 * 1000 );
 
 
-        final ArrayList<SessionStateInfoBean> gridData = new ArrayList<>();
+        final List<SessionStateInfoBean> gridData = new ArrayList<>();
         int counter = 0;
         int counter = 0;
         final Iterator<SessionStateInfoBean> infos = pwmRequest.getPwmDomain().getSessionTrackService().getSessionInfoIterator();
         final Iterator<SessionStateInfoBean> infos = pwmRequest.getPwmDomain().getSessionTrackService().getSessionInfoIterator();
         while ( counter < max && infos.hasNext() )
         while ( counter < max && infos.hasNext() )
@@ -508,7 +509,7 @@ public class AdminServlet extends ControlledPwmServlet
             gridData.add( infos.next() );
             gridData.add( infos.next() );
             counter++;
             counter++;
         }
         }
-        final RestResultBean restResultBean = RestResultBean.withData( gridData );
+        final RestResultBean restResultBean = RestResultBean.withData( gridData, List.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -534,7 +535,7 @@ public class AdminServlet extends ControlledPwmServlet
             pwmRequest.outputJsonResult( RestResultBean.fromError( errorInfo ) );
             pwmRequest.outputJsonResult( RestResultBean.fromError( errorInfo ) );
         }
         }
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( returnData );
+        final RestResultBean restResultBean = RestResultBean.withData( returnData, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -686,7 +687,9 @@ public class AdminServlet extends ControlledPwmServlet
             final DisplayElement displayElement = new DisplayElement( String.valueOf( key++ ), DisplayElement.Type.string, "Status",
             final DisplayElement displayElement = new DisplayElement( String.valueOf( key++ ), DisplayElement.Type.string, "Status",
                     "Password Notification Feature is not enabled.  See setting: "
                     "Password Notification Feature is not enabled.  See setting: "
                             + PwmSetting.PW_EXPY_NOTIFY_ENABLE.toMenuLocationDebug( null, pwmRequest.getLocale() ) );
                             + PwmSetting.PW_EXPY_NOTIFY_ENABLE.toMenuLocationDebug( null, pwmRequest.getLocale() ) );
-            pwmRequest.outputJsonResult( RestResultBean.withData( new PwNotifyStatusBean( Collections.singletonList( displayElement ), false ) ) );
+            pwmRequest.outputJsonResult( RestResultBean.withData(
+                    new PwNotifyStatusBean( Collections.singletonList( displayElement ), false ),
+                    PwNotifyStatusBean.class ) );
             return ProcessStatus.Halt;
             return ProcessStatus.Halt;
         }
         }
 
 
@@ -738,7 +741,7 @@ public class AdminServlet extends ControlledPwmServlet
 
 
         final boolean startButtonEnabled = !pwNotifyService.isRunning() && canRunOnthisServer;
         final boolean startButtonEnabled = !pwNotifyService.isRunning() && canRunOnthisServer;
         final PwNotifyStatusBean pwNotifyStatusBean = new PwNotifyStatusBean( statusData, startButtonEnabled );
         final PwNotifyStatusBean pwNotifyStatusBean = new PwNotifyStatusBean( statusData, startButtonEnabled );
-        pwmRequest.outputJsonResult( RestResultBean.withData( pwNotifyStatusBean ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( pwNotifyStatusBean, PwNotifyStatusBean.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -748,7 +751,7 @@ public class AdminServlet extends ControlledPwmServlet
     {
     {
         final PwNotifyService pwNotifyService = pwmRequest.getPwmDomain().getPwNotifyService();
         final PwNotifyService pwNotifyService = pwmRequest.getPwmDomain().getPwNotifyService();
 
 
-        pwmRequest.outputJsonResult( RestResultBean.withData( pwNotifyService.debugLog() ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( pwNotifyService.debugLog(), String.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -817,7 +820,7 @@ public class AdminServlet extends ControlledPwmServlet
         returnData.put( "display", logDisplayType );
         returnData.put( "display", logDisplayType );
         returnData.put( "size", searchResults.getReturnedEvents() );
         returnData.put( "size", searchResults.getReturnedEvents() );
         returnData.put( "duration", searchResults.getSearchTime() );
         returnData.put( "duration", searchResults.getSearchTime() );
-        pwmRequest.outputJsonResult( RestResultBean.withData( returnData ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( returnData, Map.class ) );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 8 - 6
server/src/main/java/password/pwm/http/servlet/changepw/ChangePasswordServlet.java

@@ -56,9 +56,9 @@ import password.pwm.svc.stats.AvgStatistic;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.password.PasswordUtility;
 import password.pwm.util.password.PasswordUtility;
@@ -352,8 +352,10 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
             );
             );
             passwordChangeProgress = checker.figureProgress( progressTracker );
             passwordChangeProgress = checker.figureProgress( progressTracker );
         }
         }
-        final RestResultBean restResultBean = RestResultBean.withData( passwordChangeProgress );
-        LOGGER.trace( pwmRequest, () -> "returning result for restCheckProgress: " + JsonUtil.serialize( restResultBean ) );
+        final RestResultBean<PasswordChangeProgressChecker.PasswordChangeProgress> restResultBean = RestResultBean.withData(
+                passwordChangeProgress,
+                PasswordChangeProgressChecker.PasswordChangeProgress.class );
+        LOGGER.trace( pwmRequest, () -> "returning result for restCheckProgress: " + JsonFactory.get().serialize( restResultBean ) );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -422,7 +424,7 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
     private ProcessStatus processCheckPasswordAction( final PwmRequest pwmRequest )
     private ProcessStatus processCheckPasswordAction( final PwmRequest pwmRequest )
             throws IOException, PwmUnrecoverableException, ChaiUnavailableException
             throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     {
     {
-        final RestCheckPasswordServer.JsonInput jsonInput = JsonUtil.deserialize(
+        final RestCheckPasswordServer.JsonInput jsonInput = JsonFactory.get().deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 pwmRequest.readRequestBodyAsString(),
                 RestCheckPasswordServer.JsonInput.class
                 RestCheckPasswordServer.JsonInput.class
         );
         );
@@ -440,7 +442,7 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
 
 
         final RestCheckPasswordServer.JsonOutput checkResult = RestCheckPasswordServer.JsonOutput.fromPasswordCheckInfo( passwordCheckInfo );
         final RestCheckPasswordServer.JsonOutput checkResult = RestCheckPasswordServer.JsonOutput.fromPasswordCheckInfo( passwordCheckInfo );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( checkResult );
+        final RestResultBean restResultBean = RestResultBean.withData( checkResult, RestCheckPasswordServer.JsonOutput.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -456,7 +458,7 @@ public abstract class ChangePasswordServlet extends ControlledPwmServlet
 
 
         final RestRandomPasswordServer.JsonOutput jsonOutput = new RestRandomPasswordServer.JsonOutput();
         final RestRandomPasswordServer.JsonOutput jsonOutput = new RestRandomPasswordServer.JsonOutput();
         jsonOutput.setPassword( passwordData.getStringValue() );
         jsonOutput.setPassword( passwordData.getStringValue() );
-        final RestResultBean restResultBean = RestResultBean.withData( jsonOutput );
+        final RestResultBean<RestRandomPasswordServer.JsonOutput> restResultBean = RestResultBean.withData( jsonOutput, RestRandomPasswordServer.JsonOutput.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 22 - 23
server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServlet.java

@@ -81,9 +81,9 @@ import password.pwm.svc.sms.SmsQueueService;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
 import password.pwm.util.SampleDataGenerator;
 import password.pwm.util.SampleDataGenerator;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.password.RandomPasswordGenerator;
 import password.pwm.util.password.RandomPasswordGenerator;
@@ -96,7 +96,6 @@ import javax.servlet.annotation.WebServlet;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.time.Instant;
 import java.time.Instant;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
@@ -243,7 +242,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
     {
     {
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final String bodyString = pwmRequest.readRequestBodyAsString();
         final String bodyString = pwmRequest.readRequestBodyAsString();
-        final Map<String, String> requestMap = JsonUtil.deserializeStringMap( bodyString );
+        final Map<String, String> requestMap = JsonFactory.get().deserializeStringMap( bodyString );
         final PwmSetting pwmSetting = PwmSetting.forKey( requestMap.get( "setting" ) )
         final PwmSetting pwmSetting = PwmSetting.forKey( requestMap.get( "setting" ) )
                 .orElseThrow( () -> new IllegalStateException( "invalid setting parameter value" ) );
                 .orElseThrow( () -> new IllegalStateException( "invalid setting parameter value" ) );
         final String functionName = requestMap.get( "function" );
         final String functionName = requestMap.get( "function" );
@@ -300,7 +299,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             readSettingResponse = ConfigEditorServletUtils.handleReadSetting( pwmRequest, storedConfig, key );
             readSettingResponse = ConfigEditorServletUtils.handleReadSetting( pwmRequest, storedConfig, key );
         }
         }
 
 
-        pwmRequest.outputJsonResult( RestResultBean.withData( readSettingResponse ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( readSettingResponse, ReadSettingResponse.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -339,7 +338,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             final PwmLocaleBundle pwmLocaleBundle = PwmLocaleBundle.forKey( st.nextToken() )
             final PwmLocaleBundle pwmLocaleBundle = PwmLocaleBundle.forKey( st.nextToken() )
                     .orElseThrow( () -> new IllegalArgumentException( "unknown locale bundle name" ) );
                     .orElseThrow( () -> new IllegalArgumentException( "unknown locale bundle name" ) );
             final String keyName = st.nextToken();
             final String keyName = st.nextToken();
-            final Map<String, String> valueMap = JsonUtil.deserializeStringMap( bodyString );
+            final Map<String, String> valueMap = JsonFactory.get().deserializeStringMap( bodyString );
             final Map<String, String> outputMap = new LinkedHashMap<>( valueMap );
             final Map<String, String> outputMap = new LinkedHashMap<>( valueMap );
 
 
             final DomainID domainID = DomainStateReader.forRequest( pwmRequest ).getDomainIDForLocaleBundle();
             final DomainID domainID = DomainStateReader.forRequest( pwmRequest ).getDomainIDForLocaleBundle();
@@ -367,7 +366,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
 
 
         ConfigurationCleaner.postProcessStoredConfig( modifier );
         ConfigurationCleaner.postProcessStoredConfig( modifier );
         configManagerBean.setStoredConfiguration( modifier.newStoredConfiguration() );
         configManagerBean.setStoredConfiguration( modifier.newStoredConfiguration() );
-        pwmRequest.outputJsonResult( RestResultBean.withData( readSettingResponse ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( readSettingResponse, ReadSettingResponse.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -505,7 +504,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
                 try
                 try
                 {
                 {
                     final String bodyString = pwmRequest.readRequestBodyAsString();
                     final String bodyString = pwmRequest.readRequestBodyAsString();
-                    final String value = JsonUtil.deserialize( bodyString, String.class );
+                    final String value = JsonFactory.get().deserialize( bodyString, String.class );
                     modifier.writeConfigProperty( ConfigurationProperty.NOTES, value );
                     modifier.writeConfigProperty( ConfigurationProperty.NOTES, value );
                     LOGGER.trace( () -> "updated notesText" );
                     LOGGER.trace( () -> "updated notesText" );
                 }
                 }
@@ -546,7 +545,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
 
 
         final Map<String, String> returnObj = ConfigEditorServletUtils.outputChangeLogData( pwmRequest, configManagerBean );
         final Map<String, String> returnObj = ConfigEditorServletUtils.outputChangeLogData( pwmRequest, configManagerBean );
-        final RestResultBean restResultBean = RestResultBean.withData( new LinkedHashMap<>( returnObj ) );
+        final RestResultBean restResultBean = RestResultBean.withData( returnObj, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -561,7 +560,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
 
 
         final Map<DomainID, List<String>> healthData = ConfigEditorServletUtils.configurationHealth( pwmRequest, configManagerBean );
         final Map<DomainID, List<String>> healthData = ConfigEditorServletUtils.configurationHealth( pwmRequest, configManagerBean );
-        final RestResultBean restResultBean = RestResultBean.withData( new LinkedHashMap<>( healthData ) );
+        final RestResultBean restResultBean = RestResultBean.withData( healthData, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -575,7 +574,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
     {
     {
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final ConfigManagerBean configManagerBean = getBean( pwmRequest );
         final String bodyData = pwmRequest.readRequestBodyAsString();
         final String bodyData = pwmRequest.readRequestBodyAsString();
-        final Map<String, String> valueMap = JsonUtil.deserializeStringMap( bodyData );
+        final Map<String, String> valueMap = JsonFactory.get().deserializeStringMap( bodyData );
         final Locale locale = pwmRequest.getLocale();
         final Locale locale = pwmRequest.getLocale();
         final RestResultBean restResultBean;
         final RestResultBean restResultBean;
         final String searchTerm = valueMap.get( "search" );
         final String searchTerm = valueMap.get( "search" );
@@ -606,7 +605,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
                 } );
                 } );
 
 
 
 
-        restResultBean = RestResultBean.withData( returnData );
+        restResultBean = RestResultBean.withData( returnData, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -631,7 +630,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
                 profileID,
                 profileID,
                 true,
                 true,
                 true );
                 true );
-        final RestResultBean restResultBean = RestResultBean.withData( healthData );
+        final RestResultBean restResultBean = RestResultBean.withData( healthData, PublicHealthData.class );
 
 
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         LOGGER.debug( pwmRequest, () -> "completed restLdapHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         LOGGER.debug( pwmRequest, () -> "completed restLdapHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
@@ -651,7 +650,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
         final DomainID domainID = DomainStateReader.forRequest( pwmRequest ).getDomainID( PwmSetting.LDAP_SERVER_URLS );
         final DomainID domainID = DomainStateReader.forRequest( pwmRequest ).getDomainID( PwmSetting.LDAP_SERVER_URLS );
         final List<HealthRecord> healthRecords = DatabaseStatusChecker.checkNewDatabaseStatus( pwmRequest.getPwmApplication(), config );
         final List<HealthRecord> healthRecords = DatabaseStatusChecker.checkNewDatabaseStatus( pwmRequest.getPwmApplication(), config );
         final PublicHealthData healthData = HealthRecord.asHealthDataBean( config.getDomainConfigs().get( domainID ), pwmRequest.getLocale(), healthRecords );
         final PublicHealthData healthData = HealthRecord.asHealthDataBean( config.getDomainConfigs().get( domainID ), pwmRequest.getLocale(), healthRecords );
-        final RestResultBean restResultBean = RestResultBean.withData( healthData );
+        final RestResultBean restResultBean = RestResultBean.withData( healthData, PublicHealthData.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         LOGGER.debug( pwmRequest, () -> "completed restDatabaseHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         LOGGER.debug( pwmRequest, () -> "completed restDatabaseHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -697,7 +696,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             }
             }
         }
         }
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( output.toString() );
+        final RestResultBean restResultBean = RestResultBean.withData( output.toString(), String.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         LOGGER.debug( pwmRequest, () -> "completed restSmsHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         LOGGER.debug( pwmRequest, () -> "completed restSmsHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -752,7 +751,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             output.append( "smtp service is not configured." );
             output.append( "smtp service is not configured." );
         }
         }
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( output.toString() );
+        final RestResultBean restResultBean = RestResultBean.withData( output.toString(), String.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         LOGGER.debug( pwmRequest, () -> "completed restEmailHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         LOGGER.debug( pwmRequest, () -> "completed restEmailHealthCheck in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -821,7 +820,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
                 navTreeSettings );
                 navTreeSettings );
 
 
         LOGGER.trace( pwmRequest, () -> "completed navigation tree data request in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
         LOGGER.trace( pwmRequest, () -> "completed navigation tree data request in " + TimeDuration.fromCurrent( startTime ).asCompactString() );
-        pwmRequest.outputJsonResult( RestResultBean.withData( new ArrayList<>( navigationData ) ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( navigationData, List.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -842,7 +841,7 @@ public class ConfigEditorServlet extends ControlledPwmServlet
                 navTreeSettings
                 navTreeSettings
         );
         );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( settingData );
+        final RestResultBean restResultBean = RestResultBean.withData( settingData, SettingData.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -855,14 +854,14 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             final Map<String, String> inputMap = pwmRequest.readBodyAsJsonStringMap( PwmHttpRequestWrapper.Flag.BypassValidation );
             final Map<String, String> inputMap = pwmRequest.readBodyAsJsonStringMap( PwmHttpRequestWrapper.Flag.BypassValidation );
             if ( inputMap == null || !inputMap.containsKey( "input" ) )
             if ( inputMap == null || !inputMap.containsKey( "input" ) )
             {
             {
-                pwmRequest.outputJsonResult( RestResultBean.withData( "missing input" ) );
+                pwmRequest.outputJsonResult( RestResultBean.withData( "missing input", String.class ) );
                 return ProcessStatus.Halt;
                 return ProcessStatus.Halt;
             }
             }
 
 
             final MacroRequest macroRequest = SampleDataGenerator.sampleMacroRequest( pwmRequest.getPwmDomain() );
             final MacroRequest macroRequest = SampleDataGenerator.sampleMacroRequest( pwmRequest.getPwmDomain() );
             final String input = inputMap.get( "input" );
             final String input = inputMap.get( "input" );
             final String output = macroRequest.expandMacros( input );
             final String output = macroRequest.expandMacros( input );
-            pwmRequest.outputJsonResult( RestResultBean.withData( output ) );
+            pwmRequest.outputJsonResult( RestResultBean.withData( output, String.class ) );
         }
         }
         catch ( final PwmUnrecoverableException e )
         catch ( final PwmUnrecoverableException e )
         {
         {
@@ -917,10 +916,10 @@ public class ConfigEditorServlet extends ControlledPwmServlet
             final LdapBrowser.LdapBrowseResult finalResult = result;
             final LdapBrowser.LdapBrowseResult finalResult = result;
             LOGGER.trace( pwmRequest, () -> "performed ldapBrowse operation in "
             LOGGER.trace( pwmRequest, () -> "performed ldapBrowse operation in "
                     + TimeDuration.fromCurrent( startTime ).asCompactString()
                     + TimeDuration.fromCurrent( startTime ).asCompactString()
-                    + ", result=" + JsonUtil.serialize( finalResult ) );
+                    + ", result=" + JsonFactory.get().serialize( finalResult ) );
         }
         }
 
 
-        pwmRequest.outputJsonResult( RestResultBean.withData( result ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( result, LdapBrowser.LdapBrowseResult.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -993,13 +992,13 @@ public class ConfigEditorServlet extends ControlledPwmServlet
     private ProcessStatus restRandomPassword( final PwmRequest pwmRequest )
     private ProcessStatus restRandomPassword( final PwmRequest pwmRequest )
             throws IOException, PwmUnrecoverableException
             throws IOException, PwmUnrecoverableException
     {
     {
-        final RestRandomPasswordServer.JsonInput jsonInput = JsonUtil.deserialize( pwmRequest.readRequestBodyAsString(), RestRandomPasswordServer.JsonInput.class );
+        final RestRandomPasswordServer.JsonInput jsonInput = JsonFactory.get().deserialize( pwmRequest.readRequestBodyAsString(), RestRandomPasswordServer.JsonInput.class );
         final RandomPasswordGenerator.RandomGeneratorConfig randomConfig = RestRandomPasswordServer.jsonInputToRandomConfig( jsonInput, PwmPasswordPolicy.defaultPolicy() );
         final RandomPasswordGenerator.RandomGeneratorConfig randomConfig = RestRandomPasswordServer.jsonInputToRandomConfig( jsonInput, PwmPasswordPolicy.defaultPolicy() );
         final PasswordData randomPassword = RandomPasswordGenerator.createRandomPassword( pwmRequest.getLabel(), randomConfig, pwmRequest.getPwmDomain() );
         final PasswordData randomPassword = RandomPasswordGenerator.createRandomPassword( pwmRequest.getLabel(), randomConfig, pwmRequest.getPwmDomain() );
         final RestRandomPasswordServer.JsonOutput outputMap = new RestRandomPasswordServer.JsonOutput();
         final RestRandomPasswordServer.JsonOutput outputMap = new RestRandomPasswordServer.JsonOutput();
         outputMap.setPassword( randomPassword.getStringValue() );
         outputMap.setPassword( randomPassword.getStringValue() );
 
 
-        pwmRequest.outputJsonResult( RestResultBean.withData( outputMap ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( outputMap, RestRandomPasswordServer.JsonOutput.class ) );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServletUtils.java

@@ -150,7 +150,7 @@ public class ConfigEditorServletUtils
 
 
             healthRecords.forEach( record ->
             healthRecords.forEach( record ->
                     returnData.computeIfAbsent(
                     returnData.computeIfAbsent(
-                            record.getDomainID(), k -> new ArrayList<>() )
+                                    record.getDomainID(), k -> new ArrayList<>() )
                             .add( record.getDetail( locale, pwmRequest.getAppConfig() ) ) );
                             .add( record.getDetail( locale, pwmRequest.getAppConfig() ) ) );
 
 
             LOGGER.debug( () -> "config health check done in ", () -> TimeDuration.fromCurrent( startTime ) );
             LOGGER.debug( () -> "config health check done in ", () -> TimeDuration.fromCurrent( startTime ) );
@@ -306,7 +306,7 @@ public class ConfigEditorServletUtils
                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_MISSING_PARAMETER, "unknown format type: " + e.getMessage(), new String[]
                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_MISSING_PARAMETER, "unknown format type: " + e.getMessage(), new String[]
                         {
                         {
                                 "format",
                                 "format",
-                                }
+                        }
                 ) );
                 ) );
             }
             }
 
 

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/configeditor/data/NavTreeDataMaker.java

@@ -37,7 +37,7 @@ import password.pwm.http.servlet.configeditor.DomainManageMode;
 import password.pwm.i18n.Config;
 import password.pwm.i18n.Config;
 import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -85,7 +85,7 @@ public class NavTreeDataMaker
         NavTreeDataMaker.moveNavItemToTopOfList( PwmSettingCategory.TEMPLATES.toString(), navigationData );
         NavTreeDataMaker.moveNavItemToTopOfList( PwmSettingCategory.TEMPLATES.toString(), navigationData );
         LOGGER.trace( () -> "generated " + navigationData.size()
         LOGGER.trace( () -> "generated " + navigationData.size()
                         + " navTreeItems for display menu with settings"
                         + " navTreeItems for display menu with settings"
-                        + JsonUtil.serialize( navTreeSettings ),
+                        + JsonFactory.get().serialize( navTreeSettings ),
                 () -> TimeDuration.fromCurrent( startTime ) );
                 () -> TimeDuration.fromCurrent( startTime ) );
         return Collections.unmodifiableList( navigationData );
         return Collections.unmodifiableList( navigationData );
     }
     }

+ 13 - 14
server/src/main/java/password/pwm/http/servlet/configguide/ConfigGuideServlet.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.http.servlet.configguide;
 package password.pwm.http.servlet.configguide;
 
 
-import com.google.gson.reflect.TypeToken;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import password.pwm.AppProperty;
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmApplication;
@@ -68,7 +67,7 @@ import password.pwm.i18n.Message;
 import password.pwm.ldap.LdapBrowser;
 import password.pwm.ldap.LdapBrowser;
 import password.pwm.ldap.schema.SchemaOperationResult;
 import password.pwm.ldap.schema.SchemaOperationResult;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.X509Utils;
 import password.pwm.util.secure.X509Utils;
@@ -336,7 +335,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
                 .timestamp( Instant.now() )
                 .timestamp( Instant.now() )
                 .overall( HealthUtils.getMostSevereHealthStatus( records ).toString() )
                 .overall( HealthUtils.getMostSevereHealthStatus( records ).toString() )
                 .build();
                 .build();
-        final RestResultBean restResultBean = RestResultBean.withData( jsonOutput );
+        final RestResultBean restResultBean = RestResultBean.withData( jsonOutput, PublicHealthData.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -373,9 +372,9 @@ public class ConfigGuideServlet extends ControlledPwmServlet
 
 
         LOGGER.trace( pwmRequest, () -> "performed ldapBrowse operation in "
         LOGGER.trace( pwmRequest, () -> "performed ldapBrowse operation in "
                 + TimeDuration.compactFromCurrent( startTime )
                 + TimeDuration.compactFromCurrent( startTime )
-                + ", result=" + JsonUtil.serialize( result ) );
+                + ", result=" + JsonFactory.get().serialize( result ) );
 
 
-        pwmRequest.outputJsonResult( RestResultBean.withData( result ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( result, LdapBrowser.LdapBrowseResult.class ) );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -389,9 +388,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
         final ConfigGuideBean configGuideBean = getBean( pwmRequest );
         final ConfigGuideBean configGuideBean = getBean( pwmRequest );
 
 
         final String bodyString = pwmRequest.readRequestBodyAsString();
         final String bodyString = pwmRequest.readRequestBodyAsString();
-        final Map<ConfigGuideFormField, String> incomingFormData = JsonUtil.deserialize( bodyString, new TypeToken<Map<ConfigGuideFormField, String>>()
-        {
-        } );
+        final Map<ConfigGuideFormField, String> incomingFormData = JsonFactory.get().deserializeMap( bodyString, ConfigGuideFormField.class, String.class );
 
 
         if ( incomingFormData != null )
         if ( incomingFormData != null )
         {
         {
@@ -472,7 +469,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
             }
             }
             final HashMap<String, String> resultData = new HashMap<>();
             final HashMap<String, String> resultData = new HashMap<>();
             resultData.put( "serverRestart", "true" );
             resultData.put( "serverRestart", "true" );
-            pwmRequest.outputJsonResult( RestResultBean.withData( resultData ) );
+            pwmRequest.outputJsonResult( RestResultBean.withData( resultData, Map.class ) );
             pwmRequest.invalidateSession();
             pwmRequest.invalidateSession();
         }
         }
         else
         else
@@ -498,7 +495,9 @@ public class ConfigGuideServlet extends ControlledPwmServlet
         try
         try
         {
         {
             final SchemaOperationResult schemaOperationResult = ConfigGuideUtils.extendSchema( pwmRequest.getPwmDomain(), configGuideBean, true );
             final SchemaOperationResult schemaOperationResult = ConfigGuideUtils.extendSchema( pwmRequest.getPwmDomain(), configGuideBean, true );
-            pwmRequest.outputJsonResult( RestResultBean.withData( schemaOperationResult.getOperationLog() ) );
+            pwmRequest.outputJsonResult( RestResultBean.withData(
+                    schemaOperationResult.getOperationLog(),
+                    String.class ) );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
         {
         {
@@ -578,7 +577,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
         returnMap.put( "syntax", pwmSetting.getSyntax().toString() );
         returnMap.put( "syntax", pwmSetting.getSyntax().toString() );
 
 
         returnMap.put( "value", returnValue );
         returnMap.put( "value", returnValue );
-        pwmRequest.outputJsonResult( RestResultBean.withData( returnMap ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( returnMap, Map.class ) );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -611,7 +610,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
 
 
             if ( pwmSetting == PwmSetting.CHALLENGE_RANDOM_CHALLENGES )
             if ( pwmSetting == PwmSetting.CHALLENGE_RANDOM_CHALLENGES )
             {
             {
-                configGuideBean.getFormData().put( ConfigGuideFormField.CHALLENGE_RESPONSE_DATA, JsonUtil.serialize( (Serializable) storedValue.toNativeObject() ) );
+                configGuideBean.getFormData().put( ConfigGuideFormField.CHALLENGE_RESPONSE_DATA, JsonFactory.get().serialize( (Serializable) storedValue.toNativeObject() ) );
             }
             }
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
@@ -624,7 +623,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
         returnMap.put( "category", pwmSetting.getCategory().toString() );
         returnMap.put( "category", pwmSetting.getCategory().toString() );
         returnMap.put( "syntax", pwmSetting.getSyntax().toString() );
         returnMap.put( "syntax", pwmSetting.getSyntax().toString() );
         returnMap.put( "isDefault", StoredConfigurationUtil.isDefaultValue( storedConfiguration, key ) );
         returnMap.put( "isDefault", StoredConfigurationUtil.isDefaultValue( storedConfiguration, key ) );
-        pwmRequest.outputJsonResult( RestResultBean.withData( returnMap ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( returnMap, Map.class ) );
 
 
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -645,7 +644,7 @@ public class ConfigGuideServlet extends ControlledPwmServlet
                 NavTreeSettings.forBasic()
                 NavTreeSettings.forBasic()
         );
         );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( settingData );
+        final RestResultBean restResultBean = RestResultBean.withData( settingData, SettingData.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerCertificatesServlet.java

@@ -104,7 +104,7 @@ public class ConfigManagerCertificatesServlet extends AbstractPwmServlet
 
 
         if ( action.isPresent() && action.get() == ConfigManagerCertificateAction.certificateData )
         if ( action.isPresent() && action.get() == ConfigManagerCertificateAction.certificateData )
         {
         {
-            final RestResultBean restResultBean = RestResultBean.withData( certificateDebugDataItems );
+            final RestResultBean restResultBean = RestResultBean.withData( certificateDebugDataItems, List.class );
             pwmRequest.outputJsonResult( restResultBean );
             pwmRequest.outputJsonResult( restResultBean );
             return;
             return;
         }
         }

+ 1 - 1
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerServlet.java

@@ -291,7 +291,7 @@ public class ConfigManagerServlet extends AbstractPwmServlet
         }
         }
         final HashMap<String, String> resultData = new HashMap<>();
         final HashMap<String, String> resultData = new HashMap<>();
         LOGGER.info( pwmRequest, () -> "Configuration Locked" );
         LOGGER.info( pwmRequest, () -> "Configuration Locked" );
-        pwmRequest.outputJsonResult( RestResultBean.withData( resultData ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( resultData, Map.class ) );
     }
     }
 
 
     public static void saveConfiguration(
     public static void saveConfiguration(

+ 2 - 1
server/src/main/java/password/pwm/http/servlet/configmanager/ConfigManagerWordlistServlet.java

@@ -56,6 +56,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
 
 
 @WebServlet(
 @WebServlet(
@@ -304,7 +305,7 @@ public class ConfigManagerWordlistServlet extends AbstractPwmServlet
             }
             }
             outputData.put( wordlistType, builder.build() );
             outputData.put( wordlistType, builder.build() );
         }
         }
-        pwmRequest.outputJsonResult( RestResultBean.withData( outputData ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( outputData, Map.class ) );
     }
     }
 
 
     @Value
     @Value

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordServlet.java

@@ -83,7 +83,7 @@ import password.pwm.svc.token.TokenUtil;
 import password.pwm.util.CaptchaUtility;
 import password.pwm.util.CaptchaUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -979,8 +979,8 @@ public class ForgottenPasswordServlet extends ControlledPwmServlet
                     : "";
                     : "";
             LOGGER.trace( pwmRequest, () -> "entering forgotten password progress engine: "
             LOGGER.trace( pwmRequest, () -> "entering forgotten password progress engine: "
                     + profileDebugMsg
                     + profileDebugMsg
-                    + "flags=" + JsonUtil.serialize( recoveryFlags ) + ", "
-                    + "progress=" + JsonUtil.serialize( progress ) );
+                    + "flags=" + JsonFactory.get().serialize( recoveryFlags ) + ", "
+                    + "progress=" + JsonFactory.get().serialize( progress ) );
         }
         }
 
 
         if ( forgottenPasswordProfile == null )
         if ( forgottenPasswordProfile == null )

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordStageProcessor.java

@@ -40,7 +40,7 @@ import password.pwm.ldap.UserInfo;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.password.PasswordUtility;
 import password.pwm.util.password.PasswordUtility;
 
 
@@ -152,8 +152,8 @@ class ForgottenPasswordStageProcessor
                         : "";
                         : "";
                 LOGGER.trace( sessionLabel, () -> "entering forgotten password progress engine: "
                 LOGGER.trace( sessionLabel, () -> "entering forgotten password progress engine: "
                         + profileDebugMsg
                         + profileDebugMsg
-                        + "flags=" + JsonUtil.serialize( recoveryFlags ) + ", "
-                        + "progress=" + JsonUtil.serialize( progress ) );
+                        + "flags=" + JsonFactory.get().serialize( recoveryFlags ) + ", "
+                        + "progress=" + JsonFactory.get().serialize( progress ) );
             }
             }
 
 
             if ( forgottenPasswordProfile == null )
             if ( forgottenPasswordProfile == null )

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/forgottenpw/ForgottenPasswordStateMachine.java

@@ -72,7 +72,7 @@ import password.pwm.util.PasswordData;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -135,7 +135,7 @@ public class ForgottenPasswordStateMachine
     {
     {
         this.forgottenPasswordBean = forgottenPasswordBean == null
         this.forgottenPasswordBean = forgottenPasswordBean == null
                 ? new ForgottenPasswordBean()
                 ? new ForgottenPasswordBean()
-                : JsonUtil.cloneUsingJson( forgottenPasswordBean, ForgottenPasswordBean.class );
+                : JsonFactory.get().cloneUsingJson( forgottenPasswordBean, ForgottenPasswordBean.class );
     }
     }
 
 
     public ForgottenPasswordBean getForgottenPasswordBean()
     public ForgottenPasswordBean getForgottenPasswordBean()

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/forgottenpw/RemoteVerificationMethod.java

@@ -40,7 +40,7 @@ import password.pwm.svc.httpclient.PwmHttpClient;
 import password.pwm.svc.httpclient.PwmHttpClientRequest;
 import password.pwm.svc.httpclient.PwmHttpClientRequest;
 import password.pwm.svc.httpclient.PwmHttpClientResponse;
 import password.pwm.svc.httpclient.PwmHttpClientResponse;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfo;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
 
 
@@ -153,7 +153,7 @@ public class RemoteVerificationMethod implements VerificationMethodSystem
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder()
         final PwmHttpClientRequest pwmHttpClientRequest = PwmHttpClientRequest.builder()
                 .method( HttpMethod.POST )
                 .method( HttpMethod.POST )
                 .url( url )
                 .url( url )
-                .body( JsonUtil.serialize( remoteVerificationRequestBean ) )
+                .body( JsonFactory.get().serialize( remoteVerificationRequestBean ) )
                 .headers( headers )
                 .headers( headers )
                 .build();
                 .build();
 
 
@@ -161,7 +161,7 @@ public class RemoteVerificationMethod implements VerificationMethodSystem
         {
         {
             final PwmHttpClientResponse response = pwmHttpClient.makeRequest( pwmHttpClientRequest, this.sessionLabel );
             final PwmHttpClientResponse response = pwmHttpClient.makeRequest( pwmHttpClientRequest, this.sessionLabel );
             final String responseBodyStr = response.getBody();
             final String responseBodyStr = response.getBody();
-            this.lastResponse = JsonUtil.deserialize( responseBodyStr, RemoteVerificationResponseBean.class );
+            this.lastResponse = JsonFactory.get().deserialize( responseBodyStr, RemoteVerificationResponseBean.class );
         }
         }
         catch ( final PwmException e )
         catch ( final PwmException e )
         {
         {

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskCardInfoBean.java

@@ -34,7 +34,7 @@ import password.pwm.http.PwmRequest;
 import password.pwm.http.servlet.peoplesearch.PhotoDataReader;
 import password.pwm.http.servlet.peoplesearch.PhotoDataReader;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfoFactory;
 import password.pwm.ldap.UserInfoFactory;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
@@ -96,7 +96,7 @@ public class HelpdeskCardInfoBean implements Serializable
         if ( pwmRequest.getAppConfig().isDevDebugMode() )
         if ( pwmRequest.getAppConfig().isDevDebugMode() )
         {
         {
             LOGGER.trace( pwmRequest, () -> "completed assembly of card data report for user " + userIdentity
             LOGGER.trace( pwmRequest, () -> "completed assembly of card data report for user " + userIdentity
-                    + " in " + timeDuration.asCompactString() + ", contents: " + JsonUtil.serialize( helpdeskCardInfoBean ) );
+                    + " in " + timeDuration.asCompactString() + ", contents: " + JsonFactory.get().serialize( helpdeskCardInfoBean ) );
         }
         }
 
 
         return builder.build();
         return builder.build();

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskDetailInfoBean.java

@@ -49,7 +49,7 @@ import password.pwm.ldap.ViewableUserInfoDisplayReader;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
@@ -235,7 +235,7 @@ public class HelpdeskDetailInfoBean implements Serializable
         if ( pwmRequest.getAppConfig().isDevDebugMode() )
         if ( pwmRequest.getAppConfig().isDevDebugMode() )
         {
         {
             LOGGER.trace( pwmRequest, () -> "completed assembly of detail data report for user " + userIdentity
             LOGGER.trace( pwmRequest, () -> "completed assembly of detail data report for user " + userIdentity
-                    + " in " + timeDuration.asCompactString() + ", contents: " + JsonUtil.serialize( helpdeskDetailInfoBean ) );
+                    + " in " + timeDuration.asCompactString() + ", contents: " + JsonFactory.get().serialize( helpdeskDetailInfoBean ) );
         }
         }
 
 
         return builder.build();
         return builder.build();

+ 20 - 20
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java

@@ -83,7 +83,7 @@ import password.pwm.svc.token.TokenUtil;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -228,8 +228,8 @@ public class HelpdeskServlet extends ControlledPwmServlet
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final HelpdeskClientDataBean returnValues = HelpdeskClientDataBean.fromConfig( helpdeskProfile, pwmRequest.getLocale() );
         final HelpdeskClientDataBean returnValues = HelpdeskClientDataBean.fromConfig( helpdeskProfile, pwmRequest.getLocale() );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( returnValues );
-        LOGGER.trace( pwmRequest, () -> "returning clientData: " + JsonUtil.serialize( restResultBean ) );
+        final RestResultBean restResultBean = RestResultBean.withData( returnValues, HelpdeskClientDataBean.class );
+        LOGGER.trace( pwmRequest, () -> "returning clientData: " + JsonFactory.get().serialize( restResultBean ) );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -421,7 +421,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
         final UserIdentity userIdentity = readUserKeyRequestParameter( pwmRequest );
         final UserIdentity userIdentity = readUserKeyRequestParameter( pwmRequest );
         final HelpdeskDetailInfoBean helpdeskDetailInfoBean = HelpdeskServletUtil.processDetailRequestImpl( pwmRequest, helpdeskProfile, userIdentity );
         final HelpdeskDetailInfoBean helpdeskDetailInfoBean = HelpdeskServletUtil.processDetailRequestImpl( pwmRequest, helpdeskProfile, userIdentity );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( helpdeskDetailInfoBean );
+        final RestResultBean restResultBean = RestResultBean.withData( helpdeskDetailInfoBean, HelpdeskDetailInfoBean.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -440,7 +440,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
 
 
         final HelpdeskCardInfoBean helpdeskCardInfoBean = HelpdeskCardInfoBean.makeHelpdeskCardInfo( pwmRequest, helpdeskProfile, userIdentity );
         final HelpdeskCardInfoBean helpdeskCardInfoBean = HelpdeskCardInfoBean.makeHelpdeskCardInfo( pwmRequest, helpdeskProfile, userIdentity );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( helpdeskCardInfoBean );
+        final RestResultBean restResultBean = RestResultBean.withData( helpdeskCardInfoBean, HelpdeskCardInfoBean.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -453,7 +453,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
             throws PwmUnrecoverableException, IOException
             throws PwmUnrecoverableException, IOException
     {
     {
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
-        final HelpdeskSearchRequestBean searchRequest = JsonUtil.deserialize( pwmRequest.readRequestBodyAsString(), HelpdeskSearchRequestBean.class );
+        final HelpdeskSearchRequestBean searchRequest = JsonFactory.get().deserialize( pwmRequest.readRequestBodyAsString(), HelpdeskSearchRequestBean.class );
         final HelpdeskSearchResultsBean searchResultsBean;
         final HelpdeskSearchResultsBean searchResultsBean;
 
 
         try
         try
@@ -465,7 +465,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
             throw new PwmUnrecoverableException( e.getErrorInformation() );
             throw new PwmUnrecoverableException( e.getErrorInformation() );
         }
         }
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( searchResultsBean );
+        final RestResultBean restResultBean = RestResultBean.withData( searchResultsBean, HelpdeskSearchResultsBean.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
 
 
@@ -664,7 +664,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
     {
     {
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
 
 
-        final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonUtil.deserialize(
+        final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonFactory.get().deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 pwmRequest.readRequestBodyAsString(),
                 HelpdeskVerificationRequestBean.class
                 HelpdeskVerificationRequestBean.class
         );
         );
@@ -834,7 +834,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
         final DomainSecureService domainSecureService = pwmRequest.getPwmDomain().getSecureService();
         final DomainSecureService domainSecureService = pwmRequest.getPwmDomain().getSecureService();
         helpdeskVerificationRequestBean.setTokenData( domainSecureService.encryptObjectToString( tokenData ) );
         helpdeskVerificationRequestBean.setTokenData( domainSecureService.encryptObjectToString( tokenData ) );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( helpdeskVerificationRequestBean );
+        final RestResultBean restResultBean = RestResultBean.withData( helpdeskVerificationRequestBean, HelpdeskVerificationRequestBean.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         LOGGER.debug( pwmRequest, () -> "helpdesk operator "
         LOGGER.debug( pwmRequest, () -> "helpdesk operator "
                 + pwmRequest.getUserInfoIfLoggedIn().toDisplayString()
                 + pwmRequest.getUserInfoIfLoggedIn().toDisplayString()
@@ -853,7 +853,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
     )
     )
             throws IOException, PwmUnrecoverableException, ServletException
             throws IOException, PwmUnrecoverableException, ServletException
     {
     {
-        final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonUtil.deserialize(
+        final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonFactory.get().deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 pwmRequest.readRequestBodyAsString(),
                 HelpdeskVerificationRequestBean.class
                 HelpdeskVerificationRequestBean.class
         );
         );
@@ -1002,7 +1002,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
         final HashMap<String, Object> results = new HashMap<>();
         final HashMap<String, Object> results = new HashMap<>();
         results.put( "passed", passed );
         results.put( "passed", passed );
         results.put( "verificationOptions", optionsBean );
         results.put( "verificationOptions", optionsBean );
-        final RestResultBean restResultBean = RestResultBean.withData( results );
+        final RestResultBean restResultBean = RestResultBean.withData( results, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -1025,7 +1025,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
         {
         {
             throw PwmUnrecoverableException.fromChaiException( e );
             throw PwmUnrecoverableException.fromChaiException( e );
         }
         }
-        final RestResultBean restResultBean = RestResultBean.withData( results );
+        final RestResultBean restResultBean = RestResultBean.withData( results, Map.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -1037,7 +1037,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
     {
     {
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final String bodyString = pwmRequest.readRequestBodyAsString();
         final String bodyString = pwmRequest.readRequestBodyAsString();
-        final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonUtil.deserialize(
+        final HelpdeskVerificationRequestBean helpdeskVerificationRequestBean = JsonFactory.get().deserialize(
                 bodyString,
                 bodyString,
                 HelpdeskVerificationRequestBean.class
                 HelpdeskVerificationRequestBean.class
         );
         );
@@ -1059,7 +1059,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
                 throw new PwmUnrecoverableException( errorInformation );
                 throw new PwmUnrecoverableException( errorInformation );
             }
             }
 
 
-            final Map<String, String> bodyMap = JsonUtil.deserializeStringMap( bodyString );
+            final Map<String, String> bodyMap = JsonFactory.get().deserializeStringMap( bodyString );
             final ChaiUser chaiUser = HelpdeskServletUtil.getChaiUser( pwmRequest, helpdeskProfile, userIdentity );
             final ChaiUser chaiUser = HelpdeskServletUtil.getChaiUser( pwmRequest, helpdeskProfile, userIdentity );
 
 
             int successCount = 0;
             int successCount = 0;
@@ -1136,7 +1136,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
                 passed,
                 passed,
                 verificationStateBean.toClientString( pwmRequest.getPwmDomain() )
                 verificationStateBean.toClientString( pwmRequest.getPwmDomain() )
         );
         );
-        final RestResultBean restResultBean = RestResultBean.withData( responseBean );
+        final RestResultBean restResultBean = RestResultBean.withData( responseBean, HelpdeskVerificationResponseBean.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -1208,7 +1208,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
     @ActionHandler( action = "checkPassword" )
     @ActionHandler( action = "checkPassword" )
     private ProcessStatus processCheckPasswordAction( final PwmRequest pwmRequest ) throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     private ProcessStatus processCheckPasswordAction( final PwmRequest pwmRequest ) throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     {
     {
-        final RestCheckPasswordServer.JsonInput jsonInput = JsonUtil.deserialize(
+        final RestCheckPasswordServer.JsonInput jsonInput = JsonFactory.get().deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 pwmRequest.readRequestBodyAsString(),
                 RestCheckPasswordServer.JsonInput.class
                 RestCheckPasswordServer.JsonInput.class
         );
         );
@@ -1249,7 +1249,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
 
 
         final RestCheckPasswordServer.JsonOutput jsonResponse = RestCheckPasswordServer.JsonOutput.fromPasswordCheckInfo( passwordCheckInfo );
         final RestCheckPasswordServer.JsonOutput jsonResponse = RestCheckPasswordServer.JsonOutput.fromPasswordCheckInfo( passwordCheckInfo );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( jsonResponse );
+        final RestResultBean restResultBean = RestResultBean.withData( jsonResponse, RestCheckPasswordServer.JsonOutput.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -1260,7 +1260,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
     {
     {
         final HelpdeskProfile helpdeskProfile = pwmRequest.getHelpdeskProfile( );
         final HelpdeskProfile helpdeskProfile = pwmRequest.getHelpdeskProfile( );
 
 
-        final RestSetPasswordServer.JsonInputData jsonInput = JsonUtil.deserialize(
+        final RestSetPasswordServer.JsonInputData jsonInput = JsonFactory.get().deserialize(
                 pwmRequest.readRequestBodyAsString(),
                 pwmRequest.readRequestBodyAsString(),
                 RestSetPasswordServer.JsonInputData.class
                 RestSetPasswordServer.JsonInputData.class
         );
         );
@@ -1343,7 +1343,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
     @ActionHandler( action = "randomPassword" )
     @ActionHandler( action = "randomPassword" )
     private ProcessStatus processRandomPasswordAction( final PwmRequest pwmRequest ) throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     private ProcessStatus processRandomPasswordAction( final PwmRequest pwmRequest ) throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     {
     {
-        final RestRandomPasswordServer.JsonInput input = JsonUtil.deserialize( pwmRequest.readRequestBodyAsString(), RestRandomPasswordServer.JsonInput.class );
+        final RestRandomPasswordServer.JsonInput input = JsonFactory.get().deserialize( pwmRequest.readRequestBodyAsString(), RestRandomPasswordServer.JsonInput.class );
         final UserIdentity userIdentity = UserIdentity.fromKey( pwmRequest.getLabel(), input.getUsername(), pwmRequest.getPwmApplication() );
         final UserIdentity userIdentity = UserIdentity.fromKey( pwmRequest.getLabel(), input.getUsername(), pwmRequest.getPwmApplication() );
 
 
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
         final HelpdeskProfile helpdeskProfile = getHelpdeskProfile( pwmRequest );
@@ -1369,7 +1369,7 @@ public class HelpdeskServlet extends ControlledPwmServlet
         final RestRandomPasswordServer.JsonOutput jsonOutput = new RestRandomPasswordServer.JsonOutput();
         final RestRandomPasswordServer.JsonOutput jsonOutput = new RestRandomPasswordServer.JsonOutput();
         jsonOutput.setPassword( randomPassword.getStringValue() );
         jsonOutput.setPassword( randomPassword.getStringValue() );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( jsonOutput );
+        final RestResultBean restResultBean = RestResultBean.withData( jsonOutput, RestRandomPasswordServer.JsonOutput.class );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/helpdesk/HelpdeskVerificationStateBean.java

@@ -33,7 +33,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmRequest;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfoFactory;
 import password.pwm.ldap.UserInfoFactory;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -188,7 +188,7 @@ class HelpdeskVerificationStateBean implements Serializable
 
 
         {
         {
             final HelpdeskVerificationStateBean finalState = state;
             final HelpdeskVerificationStateBean finalState = state;
-            LOGGER.debug( pwmRequest, () -> "read current state: " + JsonUtil.serialize( finalState ) );
+            LOGGER.debug( pwmRequest, () -> "read current state: " + JsonFactory.get().serialize( finalState ) );
         }
         }
 
 
         return state;
         return state;

+ 6 - 6
server/src/main/java/password/pwm/http/servlet/newuser/NewUserServlet.java

@@ -57,7 +57,7 @@ import password.pwm.svc.token.TokenType;
 import password.pwm.svc.token.TokenUtil;
 import password.pwm.svc.token.TokenUtil;
 import password.pwm.util.CaptchaUtility;
 import password.pwm.util.CaptchaUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.Percent;
 import password.pwm.util.java.Percent;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
@@ -162,7 +162,7 @@ public class NewUserServlet extends ControlledPwmServlet
         if ( StringUtil.notEmpty( signedFormData ) )
         if ( StringUtil.notEmpty( signedFormData ) )
         {
         {
             final Map<String, String> jsonForm = RestFormSigningServer.readSignedFormValue( pwmDomain, signedFormData );
             final Map<String, String> jsonForm = RestFormSigningServer.readSignedFormValue( pwmDomain, signedFormData );
-            LOGGER.trace( () -> "detected signedForm parameter in request, will read and place in bean; keys=" + JsonUtil.serializeCollection( jsonForm.keySet() ) );
+            LOGGER.trace( () -> "detected signedForm parameter in request, will read and place in bean; keys=" + JsonFactory.get().serializeCollection( jsonForm.keySet() ) );
             newUserBean.setRemoteInputData( jsonForm );
             newUserBean.setRemoteInputData( jsonForm );
         }
         }
 
 
@@ -400,7 +400,7 @@ public class NewUserServlet extends ControlledPwmServlet
             final RestCheckPasswordServer.JsonOutput jsonData = RestCheckPasswordServer.JsonOutput.fromPasswordCheckInfo(
             final RestCheckPasswordServer.JsonOutput jsonData = RestCheckPasswordServer.JsonOutput.fromPasswordCheckInfo(
                     passwordCheckInfo );
                     passwordCheckInfo );
 
 
-            final RestResultBean restResultBean = RestResultBean.withData( jsonData );
+            final RestResultBean restResultBean = RestResultBean.withData( jsonData, RestCheckPasswordServer.JsonOutput.class );
             pwmRequest.outputJsonResult( restResultBean );
             pwmRequest.outputJsonResult( restResultBean );
         }
         }
         catch ( final PwmOperationalException e )
         catch ( final PwmOperationalException e )
@@ -558,7 +558,7 @@ public class NewUserServlet extends ControlledPwmServlet
             return ProcessStatus.Continue;
             return ProcessStatus.Continue;
         }
         }
 
 
-        LOGGER.debug( pwmRequest, () -> "marking token as passed " + JsonUtil.serialize( tokenDestinationItem ) );
+        LOGGER.debug( pwmRequest, () -> "marking token as passed " + JsonFactory.get().serialize( tokenDestinationItem ) );
         newUserBean.getCompletedTokenFields().add( newUserBean.getCurrentTokenField() );
         newUserBean.getCompletedTokenFields().add( newUserBean.getCurrentTokenField() );
         newUserBean.setTokenSent( false );
         newUserBean.setTokenSent( false );
         newUserBean.setCurrentTokenField( null );
         newUserBean.setCurrentTokenField( null );
@@ -705,9 +705,9 @@ public class NewUserServlet extends ControlledPwmServlet
         outputMap.put( "percentComplete", percentComplete );
         outputMap.put( "percentComplete", percentComplete );
         outputMap.put( "complete", complete );
         outputMap.put( "complete", complete );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( outputMap );
+        final RestResultBean restResultBean = RestResultBean.withData( outputMap, Map.class );
 
 
-        LOGGER.trace( pwmRequest, () -> "returning result for restCheckProgress: " + JsonUtil.serialize( restResultBean ) );
+        LOGGER.trace( pwmRequest, () -> "returning result for restCheckProgress: " + JsonFactory.get().serialize( restResultBean ) );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/newuser/NewUserUtils.java

@@ -71,7 +71,7 @@ import password.pwm.util.PasswordData;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -437,7 +437,7 @@ class NewUserUtils
 
 
         final int attemptCountFinal = attemptCount;
         final int attemptCountFinal = attemptCount;
         NewUserUtils.LOGGER.error( pwmRequest,
         NewUserUtils.LOGGER.error( pwmRequest,
-                () -> "failed to generate new user DN after " + attemptCountFinal + " attempts, failed values: " + JsonUtil.serializeCollection(
+                () -> "failed to generate new user DN after " + attemptCountFinal + " attempts, failed values: " + JsonFactory.get().serializeCollection(
                         failedValues ) );
                         failedValues ) );
         throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_NEW_USER_FAILURE,
         throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_NEW_USER_FAILURE,
                 "unable to generate a unique DN value" ) );
                 "unable to generate a unique DN value" ) );

+ 4 - 3
server/src/main/java/password/pwm/http/servlet/oauth/OAuthConsumerServlet.java

@@ -42,7 +42,7 @@ import password.pwm.ldap.auth.PwmAuthenticationSource;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.ldap.search.UserSearchEngine;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
@@ -88,7 +88,7 @@ public class OAuthConsumerServlet extends AbstractPwmServlet
 
 
         LOGGER.trace( pwmRequest, () -> "processing oauth return request, useCase=" + oAuthUseCaseCase
         LOGGER.trace( pwmRequest, () -> "processing oauth return request, useCase=" + oAuthUseCaseCase
                 + ", incoming oAuthRequestState="
                 + ", incoming oAuthRequestState="
-                + ( oAuthRequestState.isPresent() ? JsonUtil.serialize( oAuthRequestState.get() ) : "none" )
+                + ( oAuthRequestState.isPresent() ? JsonFactory.get().serialize( oAuthRequestState.get() ) : "none" )
         );
         );
 
 
         // make sure it's okay to be processing this request.
         // make sure it's okay to be processing this request.
@@ -344,7 +344,8 @@ public class OAuthConsumerServlet extends AbstractPwmServlet
 
 
         final String nextUrl = pwmRequest.getBasePath() + PwmServletDefinition.ForgottenPassword.servletUrl();
         final String nextUrl = pwmRequest.getBasePath() + PwmServletDefinition.ForgottenPassword.servletUrl();
         final String redirectUrl = PwmURL.appendAndEncodeUrlParameters( nextUrl, httpParams );
         final String redirectUrl = PwmURL.appendAndEncodeUrlParameters( nextUrl, httpParams );
-        LOGGER.debug( pwmRequest, () -> "forgotten password oauth sequence complete, redirecting to forgotten password with result data: " + JsonUtil.serialize( results ) );
+        LOGGER.debug( pwmRequest, () -> "forgotten password oauth sequence complete, redirecting to forgotten password with result data: "
+                + JsonFactory.get().serialize( results ) );
         pwmRequest.getPwmResponse().sendRedirect( redirectUrl );
         pwmRequest.getPwmResponse().sendRedirect( redirectUrl );
     }
     }
 }
 }

+ 8 - 7
server/src/main/java/password/pwm/http/servlet/oauth/OAuthMachine.java

@@ -44,7 +44,7 @@ import password.pwm.http.servlet.PwmServletDefinition;
 import password.pwm.util.BasicAuthInfo;
 import password.pwm.util.BasicAuthInfo;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
@@ -87,11 +87,12 @@ public class OAuthMachine
         if ( requestStateStr != null )
         if ( requestStateStr != null )
         {
         {
             final String stateJson = pwmRequest.getPwmDomain().getSecureService().decryptStringValue( requestStateStr );
             final String stateJson = pwmRequest.getPwmDomain().getSecureService().decryptStringValue( requestStateStr );
-            final OAuthState oAuthState = JsonUtil.deserialize( stateJson, OAuthState.class );
+            final OAuthState oAuthState = JsonFactory.get().deserialize( stateJson, OAuthState.class );
             if ( oAuthState != null )
             if ( oAuthState != null )
             {
             {
                 final boolean sessionMatch = oAuthState.getSessionID().equals( pwmRequest.getPwmSession().getSessionStateBean().getSessionVerificationKey() );
                 final boolean sessionMatch = oAuthState.getSessionID().equals( pwmRequest.getPwmSession().getSessionStateBean().getSessionVerificationKey() );
-                LOGGER.trace( pwmRequest, () -> "read state while parsing oauth consumer request with match=" + sessionMatch + ", " + JsonUtil.serialize( oAuthState ) );
+                LOGGER.trace( pwmRequest, () -> "read state while parsing oauth consumer request with match=" + sessionMatch + ", "
+                        + JsonFactory.get().serialize( oAuthState ) );
                 return Optional.of( new OAuthRequestState( oAuthState, sessionMatch ) );
                 return Optional.of( new OAuthRequestState( oAuthState, sessionMatch ) );
             }
             }
         }
         }
@@ -429,7 +430,7 @@ public class OAuthMachine
                 + oAuthState.getStateID() + " with the next destination URL set to " + oAuthState.getNextUrl() );
                 + oAuthState.getStateID() + " with the next destination URL set to " + oAuthState.getNextUrl() );
 
 
 
 
-        final String jsonValue = JsonUtil.serialize( oAuthState );
+        final String jsonValue = JsonFactory.get().serialize( oAuthState );
         return pwmRequest.getPwmDomain().getSecureService().encryptToString( jsonValue );
         return pwmRequest.getPwmDomain().getSecureService().encryptToString( jsonValue );
     }
     }
 
 
@@ -466,14 +467,14 @@ public class OAuthMachine
             listWrapper.add( dataPayload );
             listWrapper.add( dataPayload );
 
 
             requestPayload = new HashMap<>();
             requestPayload = new HashMap<>();
-            requestPayload.put( "data", JsonUtil.serializeCollection( listWrapper ) );
+            requestPayload.put( "data", JsonFactory.get().serializeCollection( listWrapper ) );
         }
         }
 
 
         LOGGER.debug( sessionLabel, () -> "preparing to send username to OAuth /sign endpoint for future injection to /grant redirect" );
         LOGGER.debug( sessionLabel, () -> "preparing to send username to OAuth /sign endpoint for future injection to /grant redirect" );
         final PwmHttpClientResponse restResults = makeHttpRequest( pwmRequest, "OAuth pre-inject username signing service", settings, signUrl, requestPayload, null );
         final PwmHttpClientResponse restResults = makeHttpRequest( pwmRequest, "OAuth pre-inject username signing service", settings, signUrl, requestPayload, null );
 
 
         final String resultBody = restResults.getBody();
         final String resultBody = restResults.getBody();
-        final Map<String, String> resultBodyMap = JsonUtil.deserializeStringMap( resultBody );
+        final Map<String, String> resultBodyMap = JsonFactory.get().deserializeStringMap( resultBody );
         final String data = resultBodyMap.get( "data" );
         final String data = resultBodyMap.get( "data" );
         if ( StringUtil.isEmpty( data ) )
         if ( StringUtil.isEmpty( data ) )
         {
         {
@@ -490,7 +491,7 @@ public class OAuthMachine
     {
     {
         try
         try
         {
         {
-            final Map<String, Object> bodyMap = JsonUtil.deserializeMap( bodyString );
+            final Map<String, Object> bodyMap = JsonFactory.get().deserializeMap( bodyString );
             final List<String> attributeValues = StringUtil.splitAndTrim( attributeNames, "," );
             final List<String> attributeValues = StringUtil.splitAndTrim( attributeNames, "," );
 
 
             for ( final String attribute : attributeValues )
             for ( final String attribute : attributeValues )

+ 4 - 4
server/src/main/java/password/pwm/http/servlet/peoplesearch/PeopleSearchDataReader.java

@@ -65,7 +65,7 @@ import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -115,7 +115,7 @@ class PeopleSearchDataReader
     )
     )
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
-        final CacheKey cacheKey = makeCacheKey( SearchResultBean.class.getSimpleName(), JsonUtil.serialize( searchRequestBean ) );
+        final CacheKey cacheKey = makeCacheKey( SearchResultBean.class.getSimpleName(), JsonFactory.get().serialize( searchRequestBean ) );
 
 
         {
         {
             // try to serve from cache first
             // try to serve from cache first
@@ -140,7 +140,7 @@ class PeopleSearchDataReader
         storeDataInCache( cacheKey, searchResultBean );
         storeDataInCache( cacheKey, searchResultBean );
         LOGGER.trace( pwmRequest, () -> "returning " + searchResultBean.getSearchResults().size()
         LOGGER.trace( pwmRequest, () -> "returning " + searchResultBean.getSearchResults().size()
                 + " results for search request "
                 + " results for search request "
-                + JsonUtil.serialize( searchRequestBean ) );
+                + JsonFactory.get().serialize( searchRequestBean ) );
         return searchResultBean;
         return searchResultBean;
     }
     }
 
 
@@ -299,7 +299,7 @@ class PeopleSearchDataReader
         final Map<String, String> linkMap;
         final Map<String, String> linkMap;
         try
         try
         {
         {
-            linkMap = JsonUtil.deserializeStringMap( userLinksStr );
+            linkMap = JsonFactory.get().deserializeStringMap( userLinksStr );
         }
         }
         catch ( final Exception e )
         catch ( final Exception e )
         {
         {

+ 10 - 10
server/src/main/java/password/pwm/http/servlet/peoplesearch/PeopleSearchServlet.java

@@ -45,15 +45,14 @@ import password.pwm.ldap.PhotoDataBean;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.ws.server.RestResultBean;
 import password.pwm.ws.server.RestResultBean;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
 import java.io.IOException;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
@@ -127,8 +126,8 @@ public abstract class PeopleSearchServlet extends ControlledPwmServlet
                 pwmRequest.getUserInfoIfLoggedIn()
                 pwmRequest.getUserInfoIfLoggedIn()
         );
         );
 
 
-        final RestResultBean restResultBean = RestResultBean.withData( peopleSearchClientConfigBean );
-        LOGGER.trace( pwmRequest, () -> "returning clientData: " + JsonUtil.serialize( restResultBean ) );
+        final RestResultBean<PeopleSearchClientConfigBean> restResultBean = RestResultBean.withData( peopleSearchClientConfigBean, PeopleSearchClientConfigBean.class );
+        LOGGER.trace( pwmRequest, () -> "returning clientData: " + JsonFactory.get().serialize( restResultBean ) );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
@@ -139,18 +138,19 @@ public abstract class PeopleSearchServlet extends ControlledPwmServlet
     )
     )
             throws PwmUnrecoverableException, IOException
             throws PwmUnrecoverableException, IOException
     {
     {
-        final SearchRequestBean searchRequest = JsonUtil.deserialize( pwmRequest.readRequestBodyAsString(), SearchRequestBean.class );
+        final SearchRequestBean searchRequest = JsonFactory.get().deserialize( pwmRequest.readRequestBodyAsString(), SearchRequestBean.class );
 
 
         final PeopleSearchProfile peopleSearchProfile = peopleSearchProfile( pwmRequest );
         final PeopleSearchProfile peopleSearchProfile = peopleSearchProfile( pwmRequest );
         final PeopleSearchDataReader peopleSearchDataReader = new PeopleSearchDataReader( pwmRequest, peopleSearchProfile );
         final PeopleSearchDataReader peopleSearchDataReader = new PeopleSearchDataReader( pwmRequest, peopleSearchProfile );
 
 
         final SearchResultBean searchResultBean = peopleSearchDataReader.makeSearchResultBean( searchRequest );
         final SearchResultBean searchResultBean = peopleSearchDataReader.makeSearchResultBean( searchRequest );
-        final RestResultBean restResultBean = RestResultBean.withData( searchResultBean );
+        final RestResultBean<SearchResultBean> restResultBean = RestResultBean.withData( searchResultBean, SearchResultBean.class );
 
 
         addExpiresHeadersToResponse( pwmRequest );
         addExpiresHeadersToResponse( pwmRequest );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
 
 
-        LOGGER.trace( pwmRequest, () -> "returning " + searchResultBean.getSearchResults().size() + " results for search request " + JsonUtil.serialize( searchRequest ) );
+        LOGGER.trace( pwmRequest, () -> "returning " + searchResultBean.getSearchResults().size() + " results for search request "
+                + JsonFactory.get().serialize( searchRequest ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 
@@ -193,7 +193,7 @@ public abstract class PeopleSearchServlet extends ControlledPwmServlet
             final OrgChartDataBean orgChartData = peopleSearchDataReader.makeOrgChartData( userIdentity, noChildren );
             final OrgChartDataBean orgChartData = peopleSearchDataReader.makeOrgChartData( userIdentity, noChildren );
 
 
             addExpiresHeadersToResponse( pwmRequest );
             addExpiresHeadersToResponse( pwmRequest );
-            pwmRequest.outputJsonResult( RestResultBean.withData( orgChartData ) );
+            pwmRequest.outputJsonResult( RestResultBean.withData( orgChartData, OrgChartDataBean.class ) );
             StatisticsClient.incrementStat( pwmRequest, Statistic.PEOPLESEARCH_ORGCHART );
             StatisticsClient.incrementStat( pwmRequest, Statistic.PEOPLESEARCH_ORGCHART );
         }
         }
         catch ( final PwmException e )
         catch ( final PwmException e )
@@ -219,7 +219,7 @@ public abstract class PeopleSearchServlet extends ControlledPwmServlet
         final UserDetailBean detailData = peopleSearchDataReader.makeUserDetailRequest( userIdentity );
         final UserDetailBean detailData = peopleSearchDataReader.makeUserDetailRequest( userIdentity );
 
 
         addExpiresHeadersToResponse( pwmRequest );
         addExpiresHeadersToResponse( pwmRequest );
-        pwmRequest.outputJsonResult( RestResultBean.withData( detailData ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( detailData, UserDetailBean.class ) );
         StatisticsClient.incrementStat( pwmRequest, Statistic.PEOPLESEARCH_DETAILS );
         StatisticsClient.incrementStat( pwmRequest, Statistic.PEOPLESEARCH_DETAILS );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
@@ -312,7 +312,7 @@ public abstract class PeopleSearchServlet extends ControlledPwmServlet
         final int effectiveDepth = Math.max( peopleSearchConfiguration.getMailtoLinksMaxDepth(), requestedDepth );
         final int effectiveDepth = Math.max( peopleSearchConfiguration.getMailtoLinksMaxDepth(), requestedDepth );
         final List<String> mailtoLinks = peopleSearchDataReader.getMailToLink( userIdentity, effectiveDepth );
         final List<String> mailtoLinks = peopleSearchDataReader.getMailToLink( userIdentity, effectiveDepth );
 
 
-        pwmRequest.outputJsonResult( RestResultBean.withData( new ArrayList<>( mailtoLinks ) ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( mailtoLinks, List.class ) );
 
 
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 2 - 6
server/src/main/java/password/pwm/http/servlet/resource/ResourceServletConfiguration.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.http.servlet.resource;
 package password.pwm.http.servlet.resource;
 
 
-import com.google.gson.reflect.TypeToken;
 import lombok.Value;
 import lombok.Value;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.IOUtils;
@@ -32,7 +31,7 @@ import password.pwm.config.PwmSetting;
 import password.pwm.config.value.FileValue;
 import password.pwm.config.value.FileValue;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -41,7 +40,6 @@ import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.time.Instant;
 import java.time.Instant;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
@@ -141,9 +139,7 @@ class ResourceServletConfiguration
         final String zipFileResourceParam = domainConfig.getAppConfig().readAppProperty( AppProperty.HTTP_RESOURCES_ZIP_FILES );
         final String zipFileResourceParam = domainConfig.getAppConfig().readAppProperty( AppProperty.HTTP_RESOURCES_ZIP_FILES );
         if ( StringUtil.notEmpty( zipFileResourceParam ) )
         if ( StringUtil.notEmpty( zipFileResourceParam ) )
         {
         {
-            final List<ConfiguredZipFileResource> configuredZipFileResources = JsonUtil.deserialize( zipFileResourceParam, new TypeToken<ArrayList<ConfiguredZipFileResource>>()
-            {
-            } );
+            final List<ConfiguredZipFileResource> configuredZipFileResources = JsonFactory.get().deserializeList( zipFileResourceParam, ConfiguredZipFileResource.class );
             for ( final ConfiguredZipFileResource configuredZipFileResource : configuredZipFileResources )
             for ( final ConfiguredZipFileResource configuredZipFileResource : configuredZipFileResources )
             {
             {
                 final Optional<File> webInfPath = pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager().locateWebInfFilePath();
                 final Optional<File> webInfPath = pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager().locateWebInfFilePath();

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/setupresponses/SetupResponsesServlet.java

@@ -55,7 +55,7 @@ import password.pwm.svc.event.AuditServiceClient;
 import password.pwm.svc.event.UserAuditRecord;
 import password.pwm.svc.event.UserAuditRecord;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.ws.server.RestResultBean;
 import password.pwm.ws.server.RestResultBean;
@@ -307,10 +307,10 @@ public class SetupResponsesServlet extends ControlledPwmServlet
         }
         }
 
 
         final ValidationResponseBean validationResponseBean = new ValidationResponseBean( userMessage, success );
         final ValidationResponseBean validationResponseBean = new ValidationResponseBean( userMessage, success );
-        final RestResultBean restResultBean = RestResultBean.withData( validationResponseBean );
+        final RestResultBean<ValidationResponseBean> restResultBean = RestResultBean.withData( validationResponseBean, ValidationResponseBean.class );
         LOGGER.trace( pwmRequest, () -> "completed rest validate response in "
         LOGGER.trace( pwmRequest, () -> "completed rest validate response in "
                 + TimeDuration.compactFromCurrent( startTime )
                 + TimeDuration.compactFromCurrent( startTime )
-                + ", result=" + JsonUtil.serialize( restResultBean ) );
+                + ", result=" + JsonFactory.get().serialize( restResultBean ) );
         pwmRequest.outputJsonResult( restResultBean );
         pwmRequest.outputJsonResult( restResultBean );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }

+ 3 - 3
server/src/main/java/password/pwm/http/servlet/updateprofile/UpdateProfileServlet.java

@@ -57,7 +57,7 @@ import password.pwm.svc.token.TokenUtil;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.form.FormUtility;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
@@ -196,7 +196,7 @@ public class UpdateProfileServlet extends ControlledPwmServlet
             return ProcessStatus.Halt;
             return ProcessStatus.Halt;
         }
         }
 
 
-        LOGGER.debug( pwmRequest, () -> "marking token as passed " + JsonUtil.serialize( tokenDestinationItem ) );
+        LOGGER.debug( pwmRequest, () -> "marking token as passed " + JsonFactory.get().serialize( tokenDestinationItem ) );
         updateProfileBean.getCompletedTokenFields().add( updateProfileBean.getCurrentTokenField() );
         updateProfileBean.getCompletedTokenFields().add( updateProfileBean.getCurrentTokenField() );
         updateProfileBean.setTokenSent( false );
         updateProfileBean.setTokenSent( false );
         updateProfileBean.setCurrentTokenField( null );
         updateProfileBean.setCurrentTokenField( null );
@@ -248,7 +248,7 @@ public class UpdateProfileServlet extends ControlledPwmServlet
         final ValidateResponse response = new ValidateResponse();
         final ValidateResponse response = new ValidateResponse();
         response.setMessage( userMessage );
         response.setMessage( userMessage );
         response.setSuccess( success );
         response.setSuccess( success );
-        pwmRequest.outputJsonResult( RestResultBean.withData( response ) );
+        pwmRequest.outputJsonResult( RestResultBean.withData( response, ValidateResponse.class ) );
         return ProcessStatus.Halt;
         return ProcessStatus.Halt;
     }
     }
 
 

+ 2 - 2
server/src/main/java/password/pwm/http/state/CryptoCookieLoginImpl.java

@@ -37,7 +37,7 @@ import password.pwm.ldap.auth.AuthenticationType;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -201,7 +201,7 @@ class CryptoCookieLoginImpl implements SessionLoginProvider
                         );
                         );
                     }
                     }
                     remoteLoginCookie.getAuthFlags().add( AuthenticationType.AUTH_FROM_REQ_COOKIE );
                     remoteLoginCookie.getAuthFlags().add( AuthenticationType.AUTH_FROM_REQ_COOKIE );
-                    LOGGER.debug( pwmRequest, () -> "logged in using encrypted request cookie = " + JsonUtil.serialize( remoteLoginCookie ) );
+                    LOGGER.debug( pwmRequest, () -> "logged in using encrypted request cookie = " + JsonFactory.get().serialize( remoteLoginCookie ) );
                 }
                 }
                 catch ( final Exception e )
                 catch ( final Exception e )
                 {
                 {

+ 3 - 6
server/src/main/java/password/pwm/ldap/LdapConnectionService.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.ldap;
 package password.pwm.ldap;
 
 
-import com.google.gson.reflect.TypeToken;
 import com.novell.ldapchai.provider.ChaiProvider;
 import com.novell.ldapchai.provider.ChaiProvider;
 import com.novell.ldapchai.provider.ChaiProviderFactory;
 import com.novell.ldapchai.provider.ChaiProviderFactory;
 import com.novell.ldapchai.provider.ChaiSetting;
 import com.novell.ldapchai.provider.ChaiSetting;
@@ -48,7 +47,7 @@ import password.pwm.util.java.AtomicLoopIntIncrementer;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
@@ -328,7 +327,7 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
     public void setLastLdapFailure( final LdapProfile ldapProfile, final ErrorInformation errorInformation )
     public void setLastLdapFailure( final LdapProfile ldapProfile, final ErrorInformation errorInformation )
     {
     {
         lastLdapErrors.put( ldapProfile.getIdentifier(), errorInformation );
         lastLdapErrors.put( ldapProfile.getIdentifier(), errorInformation );
-        final String jsonString = JsonUtil.serializeMap( lastLdapErrors );
+        final String jsonString = JsonFactory.get().serializeMap( lastLdapErrors );
         pwmDomain.getPwmApplication().writeAppAttribute( AppAttribute.LAST_LDAP_ERROR, jsonString );
         pwmDomain.getPwmApplication().writeAppAttribute( AppAttribute.LAST_LDAP_ERROR, jsonString );
     }
     }
 
 
@@ -358,9 +357,7 @@ public class LdapConnectionService extends AbstractPwmService implements PwmServ
                 lastLdapFailureStr = optionalLastLdapError.get();
                 lastLdapFailureStr = optionalLastLdapError.get();
                 if ( StringUtil.notEmpty( lastLdapFailureStr ) )
                 if ( StringUtil.notEmpty( lastLdapFailureStr ) )
                 {
                 {
-                    final Map<String, ErrorInformation> fromJson = JsonUtil.deserialize( lastLdapFailureStr, new TypeToken<Map<String, ErrorInformation>>()
-                    {
-                    } );
+                    final Map<String, ErrorInformation> fromJson = JsonFactory.get().deserializeMap( lastLdapFailureStr, String.class, ErrorInformation.class );
                     final Map<String, ErrorInformation> returnMap = new HashMap<>( fromJson );
                     final Map<String, ErrorInformation> returnMap = new HashMap<>( fromJson );
                     returnMap.keySet().retainAll( pwmDomain.getConfig().getLdapProfiles().keySet() );
                     returnMap.keySet().retainAll( pwmDomain.getConfig().getLdapProfiles().keySet() );
                     return returnMap;
                     return returnMap;

+ 2 - 2
server/src/main/java/password/pwm/ldap/PasswordChangeProgressChecker.java

@@ -35,7 +35,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.Display;
 import password.pwm.util.ProgressInfo;
 import password.pwm.util.ProgressInfo;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.Percent;
 import password.pwm.util.java.Percent;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -338,7 +338,7 @@ public class PasswordChangeProgressChecker
                 }
                 }
                 final Percent pctComplete = Percent.of( duplicateValues + 1, checkResults.size() );
                 final Percent pctComplete = Percent.of( duplicateValues + 1, checkResults.size() );
                 final ProgressRecord progressRecord = makeReplicaProgressRecord( pctComplete );
                 final ProgressRecord progressRecord = makeReplicaProgressRecord( pctComplete );
-                LOGGER.trace( () -> "read password replication sync status as: " + JsonUtil.serialize( progressRecord ) );
+                LOGGER.trace( () -> "read password replication sync status as: " + JsonFactory.get().serialize( progressRecord ) );
                 return Optional.of( progressRecord );
                 return Optional.of( progressRecord );
             }
             }
         }
         }

+ 2 - 5
server/src/main/java/password/pwm/ldap/auth/SessionAuthenticator.java

@@ -20,7 +20,6 @@
 
 
 package password.pwm.ldap.auth;
 package password.pwm.ldap.auth;
 
 
-import com.google.gson.reflect.TypeToken;
 import com.novell.ldapchai.ChaiConstant;
 import com.novell.ldapchai.ChaiConstant;
 import com.novell.ldapchai.exception.ChaiError;
 import com.novell.ldapchai.exception.ChaiError;
 import com.novell.ldapchai.exception.ChaiException;
 import com.novell.ldapchai.exception.ChaiException;
@@ -52,7 +51,7 @@ import password.pwm.svc.intruder.IntruderServiceClient;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -139,9 +138,7 @@ public class SessionAuthenticator
         {
         {
             try
             try
             {
             {
-                final List<Integer> configuredNumbers = JsonUtil.deserialize( appProperty, new TypeToken<List<Integer>>()
-                {
-                } );
+                final List<Integer> configuredNumbers = JsonFactory.get().deserializeList( appProperty, Integer.class );
                 for ( final Integer errorCode : configuredNumbers )
                 for ( final Integer errorCode : configuredNumbers )
                 {
                 {
                     final PwmError pwmError = PwmError.forErrorNumber( errorCode ).orElse( PwmError.ERROR_INTERNAL );
                     final PwmError pwmError = PwmError.forErrorNumber( errorCode ).orElse( PwmError.ERROR_INTERNAL );

+ 3 - 3
server/src/main/java/password/pwm/ldap/schema/EdirSchemaExtender.java

@@ -28,7 +28,7 @@ import com.novell.ldapchai.provider.ChaiProvider;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.io.IOException;
 import java.io.IOException;
@@ -246,9 +246,9 @@ public class EdirSchemaExtender implements SchemaExtender
                 if ( !defOptionals.equals( existingOptionals ) )
                 if ( !defOptionals.equals( existingOptionals ) )
                 {
                 {
                     logActivity( "objectclass '" + schemaDefinition.getName()
                     logActivity( "objectclass '" + schemaDefinition.getName()
-                            + "' optional attributes (" + JsonUtil.serializeCollection( defOptionals )
+                            + "' optional attributes (" + JsonFactory.get().serializeCollection( defOptionals )
                             + ") is not correct, correct optional attribute list is ("
                             + ") is not correct, correct optional attribute list is ("
-                            + JsonUtil.serializeCollection( existingOptionals ) + ")" );
+                            + JsonFactory.get().serializeCollection( existingOptionals ) + ")" );
                     checkPassed = false;
                     checkPassed = false;
                 }
                 }
             }
             }

+ 2 - 2
server/src/main/java/password/pwm/ldap/schema/SchemaDefinition.java

@@ -20,7 +20,7 @@
 
 
 package password.pwm.ldap.schema;
 package password.pwm.ldap.schema;
 
 
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.io.Serializable;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.ArrayList;
@@ -49,7 +49,7 @@ public class SchemaDefinition implements Serializable
         for ( final String key : Collections.list( resourceBundle.getKeys() ) )
         for ( final String key : Collections.list( resourceBundle.getKeys() ) )
         {
         {
             final String value = resourceBundle.getString( key );
             final String value = resourceBundle.getString( key );
-            final SchemaDefinition schemaDefinition = JsonUtil.deserialize( value, SchemaDefinition.class );
+            final SchemaDefinition schemaDefinition = JsonFactory.get().deserialize( value, SchemaDefinition.class );
             returnObj.put( key, schemaDefinition );
             returnObj.put( key, schemaDefinition );
         }
         }
         return new ArrayList<>( returnObj.values() );
         return new ArrayList<>( returnObj.values() );

+ 2 - 2
server/src/main/java/password/pwm/ldap/search/UserSearchEngine.java

@@ -49,7 +49,7 @@ import password.pwm.util.java.AtomicLoopIntIncrementer;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
@@ -378,7 +378,7 @@ public class UserSearchEngine extends AbstractPwmService implements PwmService
                             errors.add( e.getErrorInformation().getDetailedErrorMsg() );
                             errors.add( e.getErrorInformation().getDetailedErrorMsg() );
                             if ( errors.size() >= ldapProfiles.size() )
                             if ( errors.size() >= ldapProfiles.size() )
                             {
                             {
-                                final String errorMsg = "all ldap profiles are unreachable; errors: " + JsonUtil.serializeCollection( errors );
+                                final String errorMsg = "all ldap profiles are unreachable; errors: " + JsonFactory.get().serializeCollection( errors );
                                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_DIRECTORY_UNAVAILABLE, errorMsg ) );
                                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_DIRECTORY_UNAVAILABLE, errorMsg ) );
                             }
                             }
                         }
                         }

+ 6 - 6
server/src/main/java/password/pwm/svc/cache/CacheService.java

@@ -29,7 +29,7 @@ import password.pwm.health.HealthRecord;
 import password.pwm.svc.AbstractPwmService;
 import password.pwm.svc.AbstractPwmService;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.PwmService;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.ConditionalTaskExecutor;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -104,15 +104,15 @@ public class CacheService extends AbstractPwmService implements PwmService
         final Map<String, String> debugInfo = new TreeMap<>( );
         final Map<String, String> debugInfo = new TreeMap<>( );
         debugInfo.put( "itemCount", String.valueOf( memoryCacheStore.itemCount() ) );
         debugInfo.put( "itemCount", String.valueOf( memoryCacheStore.itemCount() ) );
         debugInfo.put( "byteCount", String.valueOf( memoryCacheStore.byteCount() ) );
         debugInfo.put( "byteCount", String.valueOf( memoryCacheStore.byteCount() ) );
-        debugInfo.putAll( JsonUtil.deserializeStringMap( JsonUtil.serializeMap( memoryCacheStore.getCacheStoreInfo().debugStats() ) ) );
-        debugInfo.putAll( JsonUtil.deserializeStringMap( JsonUtil.serializeMap( memoryCacheStore.storedClassHistogram( "histogram." ) ) ) );
+        debugInfo.putAll( JsonFactory.get().deserializeStringMap( JsonFactory.get().serializeMap( memoryCacheStore.getCacheStoreInfo().debugStats() ) ) );
+        debugInfo.putAll( JsonFactory.get().deserializeStringMap( JsonFactory.get().serializeMap( memoryCacheStore.storedClassHistogram( "histogram." ) ) ) );
         return ServiceInfoBean.builder().debugProperties( debugInfo ).build();
         return ServiceInfoBean.builder().debugProperties( debugInfo ).build();
     }
     }
 
 
     public Map<String, Serializable> debugInfo( )
     public Map<String, Serializable> debugInfo( )
     {
     {
         final Map<String, Serializable> debugInfo = new LinkedHashMap<>( );
         final Map<String, Serializable> debugInfo = new LinkedHashMap<>( );
-        debugInfo.put( "memory-statistics", JsonUtil.serializeMap( memoryCacheStore.getCacheStoreInfo().debugStats() ) );
+        debugInfo.put( "memory-statistics", JsonFactory.get().serializeMap( memoryCacheStore.getCacheStoreInfo().debugStats() ) );
         debugInfo.put( "memory-items", new ArrayList<Serializable>( memoryCacheStore.getCacheDebugItems() ) );
         debugInfo.put( "memory-items", new ArrayList<Serializable>( memoryCacheStore.getCacheDebugItems() ) );
         debugInfo.put( "memory-histogram", new HashMap<>( memoryCacheStore.storedClassHistogram( "" ) ) );
         debugInfo.put( "memory-histogram", new HashMap<>( memoryCacheStore.storedClassHistogram( "" ) ) );
         return Collections.unmodifiableMap( debugInfo );
         return Collections.unmodifiableMap( debugInfo );
@@ -183,9 +183,9 @@ public class CacheService extends AbstractPwmService implements PwmService
         {
         {
             final StatisticCounterBundle<CacheStore.DebugKey> info = memoryCacheStore.getCacheStoreInfo();
             final StatisticCounterBundle<CacheStore.DebugKey> info = memoryCacheStore.getCacheStoreInfo();
             traceOutput.append( "memCache=" );
             traceOutput.append( "memCache=" );
-            traceOutput.append( JsonUtil.serializeMap( info.debugStats() ) );
+            traceOutput.append( JsonFactory.get().serializeMap( info.debugStats() ) );
             traceOutput.append( ", histogram=" );
             traceOutput.append( ", histogram=" );
-            traceOutput.append( JsonUtil.serializeMap( memoryCacheStore.storedClassHistogram( "" ) ) );
+            traceOutput.append( JsonFactory.get().serializeMap( memoryCacheStore.storedClassHistogram( "" ) ) );
         }
         }
         LOGGER.trace( () -> traceOutput );
         LOGGER.trace( () -> traceOutput );
     }
     }

+ 4 - 4
server/src/main/java/password/pwm/svc/cache/MemoryCacheStore.java

@@ -25,7 +25,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
 import lombok.Value;
 import lombok.Value;
 import password.pwm.bean.UserIdentity;
 import password.pwm.bean.UserIdentity;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -56,7 +56,7 @@ class MemoryCacheStore implements CacheStore
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
         cacheStoreInfo.increment( DebugKey.storeCount );
         cacheStoreInfo.increment( DebugKey.storeCount );
-        final String jsonData = JsonUtil.serialize( data );
+        final String jsonData = JsonFactory.get().serialize( data );
         memoryStore.put( cacheKey, new CacheValueWrapper( cacheKey, expirationDate, jsonData ) );
         memoryStore.put( cacheKey, new CacheValueWrapper( cacheKey, expirationDate, jsonData ) );
     }
     }
 
 
@@ -75,7 +75,7 @@ class MemoryCacheStore implements CacheStore
         }
         }
 
 
         final T data = cacheLoader.read();
         final T data = cacheLoader.read();
-        final String jsonIfiedData = JsonUtil.serialize( data );
+        final String jsonIfiedData = JsonFactory.get().serialize( data );
         cacheStoreInfo.increment( DebugKey.missCount );
         cacheStoreInfo.increment( DebugKey.missCount );
         memoryStore.put( cacheKey, new CacheValueWrapper( cacheKey, expirationDate, jsonIfiedData ) );
         memoryStore.put( cacheKey, new CacheValueWrapper( cacheKey, expirationDate, jsonIfiedData ) );
         return data;
         return data;
@@ -91,7 +91,7 @@ class MemoryCacheStore implements CacheStore
                 {
                 {
                     cacheStoreInfo.increment( DebugKey.hitCount );
                     cacheStoreInfo.increment( DebugKey.hitCount );
                     final String jsonValue  = valueWrapper.getPayload();
                     final String jsonValue  = valueWrapper.getPayload();
-                    return JsonUtil.deserialize( jsonValue, classOfT );
+                    return JsonFactory.get().deserialize( jsonValue, classOfT );
                 }
                 }
             }
             }
         }
         }

+ 8 - 8
server/src/main/java/password/pwm/svc/cr/CrService.java

@@ -60,7 +60,7 @@ import password.pwm.svc.AbstractPwmService;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.wordlist.WordlistService;
 import password.pwm.svc.wordlist.WordlistService;
 import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.CollectionUtil;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -172,7 +172,7 @@ public class CrService extends AbstractPwmService implements PwmService
 
 
                         LOGGER.debug( sessionLabel, () -> "using ldap c/r policy for user " + theUser.getEntryDN() + ": "
                         LOGGER.debug( sessionLabel, () -> "using ldap c/r policy for user " + theUser.getEntryDN() + ": "
                                 + finalReturnSet.toString() );
                                 + finalReturnSet.toString() );
-                        LOGGER.trace( sessionLabel, () -> "readUserChallengeProfile completed, result=" + JsonUtil.serialize( challengeProfile ),
+                        LOGGER.trace( sessionLabel, () -> "readUserChallengeProfile completed, result=" + JsonFactory.get().serialize( challengeProfile ),
                                 () -> TimeDuration.fromCurrent( methodStartTime ) );
                                 () -> TimeDuration.fromCurrent( methodStartTime ) );
 
 
                         return challengeProfile;
                         return challengeProfile;
@@ -414,7 +414,7 @@ public class CrService extends AbstractPwmService implements PwmService
         final List<DataStorageMethod> readPreferences = config.getCrReadPreference();
         final List<DataStorageMethod> readPreferences = config.getCrReadPreference();
 
 
         final String debugMsg = "will attempt to read the following storage methods: "
         final String debugMsg = "will attempt to read the following storage methods: "
-                + JsonUtil.serializeCollection( readPreferences ) + " for response info for user " + theUser.getEntryDN();
+                + JsonFactory.get().serializeCollection( readPreferences ) + " for response info for user " + theUser.getEntryDN();
         LOGGER.debug( sessionLabel, () -> debugMsg );
         LOGGER.debug( sessionLabel, () -> debugMsg );
 
 
         final String userGUID;
         final String userGUID;
@@ -463,7 +463,7 @@ public class CrService extends AbstractPwmService implements PwmService
         final List<DataStorageMethod> readPreferences = config.getCrReadPreference();
         final List<DataStorageMethod> readPreferences = config.getCrReadPreference();
 
 
         LOGGER.debug( sessionLabel, () -> "will attempt to read the following storage methods: "
         LOGGER.debug( sessionLabel, () -> "will attempt to read the following storage methods: "
-                + JsonUtil.serializeCollection( readPreferences ) + " for user " + theUser.getEntryDN() );
+                + JsonFactory.get().serializeCollection( readPreferences ) + " for user " + theUser.getEntryDN() );
 
 
         final String userGUID;
         final String userGUID;
         if ( readPreferences.contains( DataStorageMethod.DB ) || readPreferences.contains( DataStorageMethod.LOCALDB ) )
         if ( readPreferences.contains( DataStorageMethod.DB ) || readPreferences.contains( DataStorageMethod.LOCALDB ) )
@@ -513,7 +513,7 @@ public class CrService extends AbstractPwmService implements PwmService
         final List<DataStorageMethod> writeMethods = pwmDomain.getConfig().getCrWritePreference( );
         final List<DataStorageMethod> writeMethods = pwmDomain.getConfig().getCrWritePreference( );
 
 
         LOGGER.debug( sessionLabel, () -> "will attempt to write the following storage methods: "
         LOGGER.debug( sessionLabel, () -> "will attempt to write the following storage methods: "
-                + JsonUtil.serializeCollection( writeMethods ) + " for user " + theUser.getEntryDN() );
+                + JsonFactory.get().serializeCollection( writeMethods ) + " for user " + theUser.getEntryDN() );
 
 
 
 
         for ( final DataStorageMethod loopWriteMethod : writeMethods )
         for ( final DataStorageMethod loopWriteMethod : writeMethods )
@@ -544,7 +544,7 @@ public class CrService extends AbstractPwmService implements PwmService
         if ( successes == 0 )
         if ( successes == 0 )
         {
         {
             final String errorMsg = "response storage unsuccessful; attempts=" + attempts + ", successes=" + successes
             final String errorMsg = "response storage unsuccessful; attempts=" + attempts + ", successes=" + successes
-                    + ", detail=" + JsonUtil.serializeMap( errorMessages );
+                    + ", detail=" + JsonFactory.get().serializeMap( errorMessages, DataStorageMethod.class, String.class );
             final ErrorInformation errorInfo = new ErrorInformation( PwmError.ERROR_WRITING_RESPONSES, errorMsg );
             final ErrorInformation errorInfo = new ErrorInformation( PwmError.ERROR_WRITING_RESPONSES, errorMsg );
             throw new PwmOperationalException( errorInfo );
             throw new PwmOperationalException( errorInfo );
         }
         }
@@ -552,7 +552,7 @@ public class CrService extends AbstractPwmService implements PwmService
         if ( attempts != successes )
         if ( attempts != successes )
         {
         {
             final String errorMsg = "response storage only partially successful; attempts=" + attempts + ", successes=" + successes
             final String errorMsg = "response storage only partially successful; attempts=" + attempts + ", successes=" + successes
-                    + ", detail=" + JsonUtil.serializeMap( errorMessages );
+                    + ", detail=" + JsonFactory.get().serializeMap( errorMessages, DataStorageMethod.class, String.class );
             final ErrorInformation errorInfo = new ErrorInformation( PwmError.ERROR_WRITING_RESPONSES, errorMsg );
             final ErrorInformation errorInfo = new ErrorInformation( PwmError.ERROR_WRITING_RESPONSES, errorMsg );
             throw new PwmOperationalException( errorInfo );
             throw new PwmOperationalException( errorInfo );
         }
         }
@@ -574,7 +574,7 @@ public class CrService extends AbstractPwmService implements PwmService
         final List<DataStorageMethod> writeMethods = pwmDomain.getConfig().getCrWritePreference();
         final List<DataStorageMethod> writeMethods = pwmDomain.getConfig().getCrWritePreference();
 
 
         LOGGER.debug( sessionLabel, () -> "will attempt to clear the following storage methods: "
         LOGGER.debug( sessionLabel, () -> "will attempt to clear the following storage methods: "
-                + JsonUtil.serializeCollection( writeMethods ) + " for user " + theUser.getEntryDN()
+                + JsonFactory.get().serializeCollection( writeMethods ) + " for user " + theUser.getEntryDN()
                 + theUser.getEntryDN() + " guid=" + userGUID );
                 + theUser.getEntryDN() + " guid=" + userGUID );
 
 
         for ( final DataStorageMethod loopWriteMethod : writeMethods )
         for ( final DataStorageMethod loopWriteMethod : writeMethods )

+ 2 - 2
server/src/main/java/password/pwm/svc/cr/NMASCrOperator.java

@@ -78,7 +78,7 @@ import password.pwm.ldap.LdapOperationsHelper;
 import password.pwm.svc.intruder.IntruderServiceClient;
 import password.pwm.svc.intruder.IntruderServiceClient;
 import password.pwm.util.PasswordData;
 import password.pwm.util.PasswordData;
 import password.pwm.util.java.AtomicLoopIntIncrementer;
 import password.pwm.util.java.AtomicLoopIntIncrementer;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -1024,7 +1024,7 @@ public class NMASCrOperator implements CrOperator
             debugInfo.put( "loginResultReady", Boolean.toString( this.loginResultReady ) );
             debugInfo.put( "loginResultReady", Boolean.toString( this.loginResultReady ) );
             debugInfo.put( "idleTime", TimeDuration.fromCurrent( this.getLastActivityTimestamp() ).asCompactString() );
             debugInfo.put( "idleTime", TimeDuration.fromCurrent( this.getLastActivityTimestamp() ).asCompactString() );
 
 
-            return "NMASSessionThread: " + JsonUtil.serialize( debugInfo );
+            return "NMASSessionThread: " + JsonFactory.get().serialize( debugInfo );
         }
         }
     }
     }
 
 

+ 3 - 3
server/src/main/java/password/pwm/svc/db/DatabaseAccessorImpl.java

@@ -21,7 +21,7 @@
 package password.pwm.svc.db;
 package password.pwm.svc.db;
 
 
 import password.pwm.util.java.ClosableIterator;
 import password.pwm.util.java.ClosableIterator;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
@@ -475,7 +475,7 @@ class DatabaseAccessorImpl implements DatabaseAccessor
             return;
             return;
         }
         }
 
 
-        LOGGER.trace( () -> "accessor #" + accessorNumber + " begin operation: " + JsonUtil.serialize( debugInfo ) );
+        LOGGER.trace( () -> "accessor #" + accessorNumber + " begin operation: " + JsonFactory.get().serialize( debugInfo ) );
     }
     }
 
 
     private void traceResult(
     private void traceResult(
@@ -488,7 +488,7 @@ class DatabaseAccessorImpl implements DatabaseAccessor
             return;
             return;
         }
         }
 
 
-        final Map<String, String> map = JsonUtil.deserializeStringMap( JsonUtil.serialize( debugInfo ) );
+        final Map<String, String> map = JsonFactory.get().deserializeStringMap( JsonFactory.get().serialize( debugInfo ) );
         map.put( "duration", TimeDuration.fromCurrent( debugInfo.getStartTime() ).asCompactString() );
         map.put( "duration", TimeDuration.fromCurrent( debugInfo.getStartTime() ).asCompactString() );
         if ( result != null )
         if ( result != null )
         {
         {

+ 4 - 3
server/src/main/java/password/pwm/svc/db/DatabaseService.java

@@ -38,7 +38,7 @@ import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.PwmScheduler;
 import password.pwm.util.PwmScheduler;
 import password.pwm.util.java.AtomicLoopIntIncrementer;
 import password.pwm.util.java.AtomicLoopIntIncrementer;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
@@ -145,7 +145,8 @@ public class DatabaseService extends AbstractPwmService implements PwmService
 
 
                 final Connection connection = openConnection( dbConfiguration );
                 final Connection connection = openConnection( dbConfiguration );
                 updateDebugProperties( connection );
                 updateDebugProperties( connection );
-                LOGGER.debug( () -> "established initial connection to " + dbConfiguration.getConnectionString() + ", properties: " + JsonUtil.serializeMap( this.debugInfo ) );
+                LOGGER.debug( () -> "established initial connection to " + dbConfiguration.getConnectionString() + ", properties: "
+                        + JsonFactory.get().serializeMap( this.debugInfo ) );
 
 
                 for ( final DatabaseTable table : DatabaseTable.values() )
                 for ( final DatabaseTable table : DatabaseTable.values() )
                 {
                 {
@@ -245,7 +246,7 @@ public class DatabaseService extends AbstractPwmService implements PwmService
             final Map<String, String> tempMap = new HashMap<>();
             final Map<String, String> tempMap = new HashMap<>();
             tempMap.put( "date", JavaHelper.toIsoDate( Instant.now() ) );
             tempMap.put( "date", JavaHelper.toIsoDate( Instant.now() ) );
             final DatabaseAccessor accessor = getAccessor();
             final DatabaseAccessor accessor = getAccessor();
-            accessor.put( DatabaseTable.PWM_META, KEY_TEST, JsonUtil.serializeMap( tempMap ) );
+            accessor.put( DatabaseTable.PWM_META, KEY_TEST, JsonFactory.get().serializeMap( tempMap ) );
         }
         }
         catch ( final PwmException e )
         catch ( final PwmException e )
         {
         {

+ 3 - 3
server/src/main/java/password/pwm/svc/db/JDBCDriverLoader.java

@@ -30,7 +30,7 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.http.bean.ImmutableByteArray;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedOutputStream;
@@ -63,7 +63,7 @@ public class JDBCDriverLoader
             throws DatabaseException
             throws DatabaseException
     {
     {
         final Set<ClassLoaderStrategy> strategies = dbConfiguration.getClassLoaderStrategies();
         final Set<ClassLoaderStrategy> strategies = dbConfiguration.getClassLoaderStrategies();
-        LOGGER.trace( () -> "attempting to load jdbc driver using strategies: " + JsonUtil.serializeCollection( strategies ) );
+        LOGGER.trace( () -> "attempting to load jdbc driver using strategies: " + JsonFactory.get().serializeCollection( strategies ) );
         final List<String> errorMsgs = new ArrayList<>();
         final List<String> errorMsgs = new ArrayList<>();
         for ( final ClassLoaderStrategy strategy : strategies )
         for ( final ClassLoaderStrategy strategy : strategies )
         {
         {
@@ -81,7 +81,7 @@ public class JDBCDriverLoader
                 errorMsgs.add( strategy + " error: " + e.getMessage() );
                 errorMsgs.add( strategy + " error: " + e.getMessage() );
             }
             }
         }
         }
-        final String errorMsg = " unable to load database driver: " + JsonUtil.serializeCollection( errorMsgs );
+        final String errorMsg = " unable to load database driver: " + JsonFactory.get().serializeCollection( errorMsgs );
         final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_DB_UNAVAILABLE, errorMsg );
         final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_DB_UNAVAILABLE, errorMsg );
         LOGGER.error( () -> errorMsg );
         LOGGER.error( () -> errorMsg );
         throw new DatabaseException( errorInformation );
         throw new DatabaseException( errorInformation );

+ 3 - 3
server/src/main/java/password/pwm/svc/email/EmailService.java

@@ -43,7 +43,7 @@ import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.ConditionalTaskExecutor;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.java.TimeDuration;
@@ -90,7 +90,7 @@ public class EmailService extends AbstractPwmService implements PwmService
             throws PwmException
             throws PwmException
     {
     {
         this.emailServiceSettings = EmailServiceSettings.fromConfiguration( this.getPwmApplication().getConfig() );
         this.emailServiceSettings = EmailServiceSettings.fromConfiguration( this.getPwmApplication().getConfig() );
-        LOGGER.trace( () -> "initializing with settings: " + JsonUtil.serialize( emailServiceSettings ) );
+        LOGGER.trace( () -> "initializing with settings: " + JsonFactory.get().serialize( emailServiceSettings ) );
 
 
         final List<EmailServer> servers;
         final List<EmailServer> servers;
         try
         try
@@ -117,7 +117,7 @@ public class EmailService extends AbstractPwmService implements PwmService
 
 
         }
         }
 
 
-        LOGGER.debug( () -> "starting with settings: " + JsonUtil.serialize( emailServiceSettings ) );
+        LOGGER.debug( () -> "starting with settings: " + JsonFactory.get().serialize( emailServiceSettings ) );
 
 
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
         final WorkQueueProcessor.Settings settings = WorkQueueProcessor.Settings.builder()
                 .maxEvents( emailServiceSettings.getQueueMaxItems() )
                 .maxEvents( emailServiceSettings.getQueueMaxItems() )

+ 2 - 2
server/src/main/java/password/pwm/svc/event/AuditEvent.java

@@ -24,7 +24,7 @@ import password.pwm.config.SettingReader;
 import password.pwm.i18n.Admin;
 import password.pwm.i18n.Admin;
 import password.pwm.i18n.Message;
 import password.pwm.i18n.Message;
 import password.pwm.i18n.PwmDisplayBundle;
 import password.pwm.i18n.PwmDisplayBundle;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
@@ -156,6 +156,6 @@ public enum AuditEvent
     {
     {
         final ResourceBundle resourceBundle = ResourceBundle.getBundle( AuditEvent.class.getName() );
         final ResourceBundle resourceBundle = ResourceBundle.getBundle( AuditEvent.class.getName() );
         final String jsonObj = resourceBundle.getString( this.toString() );
         final String jsonObj = resourceBundle.getString( this.toString() );
-        return JsonUtil.deserializeStringMap( jsonObj );
+        return JsonFactory.get().deserializeStringMap( jsonObj );
     }
     }
 }
 }

+ 2 - 2
server/src/main/java/password/pwm/svc/event/AuditRecordFactory.java

@@ -35,7 +35,7 @@ import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfoFactory;
 import password.pwm.ldap.UserInfoFactory;
 import password.pwm.svc.userhistory.LdapXmlUserHistory;
 import password.pwm.svc.userhistory.LdapXmlUserHistory;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.secure.PwmRandom;
@@ -273,7 +273,7 @@ public class AuditRecordFactory
             outputString = macroRequest.expandMacros( outputString );
             outputString = macroRequest.expandMacros( outputString );
         }
         }
 
 
-        final Map<String, String> recordFields = JsonUtil.deserializeStringMap( JsonUtil.serialize( auditRecord ) );
+        final Map<String, String> recordFields = JsonFactory.get().deserializeStringMap( JsonFactory.get().serialize( auditRecord ) );
         for ( final Map.Entry<String, String> entry : recordFields.entrySet() )
         for ( final Map.Entry<String, String> entry : recordFields.entrySet() )
         {
         {
             final String key = entry.getKey();
             final String key = entry.getKey();

+ 6 - 5
server/src/main/java/password/pwm/svc/event/AuditService.java

@@ -45,7 +45,7 @@ import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.svc.stats.StatisticsClient;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDB;
@@ -202,8 +202,8 @@ public class AuditService extends AbstractPwmService implements PwmService
 
 
         final String body;
         final String body;
         {
         {
-            final String jsonRecord = JsonUtil.serialize( record );
-            final Map<String, Object> mapRecord = JsonUtil.deserializeMap( jsonRecord );
+            final String jsonRecord = JsonFactory.get().serialize( record );
+            final Map<String, Object> mapRecord = JsonFactory.get().deserializeMap( jsonRecord );
             body = StringUtil.mapToString( mapRecord, "=", "\n" );
             body = StringUtil.mapToString( mapRecord, "=", "\n" );
         }
         }
 
 
@@ -238,7 +238,7 @@ public class AuditService extends AbstractPwmService implements PwmService
     public void submit( final SessionLabel sessionLabel, final AuditRecord auditRecord )
     public void submit( final SessionLabel sessionLabel, final AuditRecord auditRecord )
             throws PwmUnrecoverableException
             throws PwmUnrecoverableException
     {
     {
-        final String jsonRecord = JsonUtil.serialize( auditRecord );
+        final String jsonRecord = JsonFactory.get().serialize( auditRecord );
 
 
         if ( status() != STATUS.OPEN )
         if ( status() != STATUS.OPEN )
         {
         {
@@ -293,7 +293,8 @@ public class AuditService extends AbstractPwmService implements PwmService
                     }
                     }
                     else
                     else
                     {
                     {
-                        LOGGER.trace( sessionLabel, () -> "skipping update of user history, audit record does not have a perpetratorDN: " + JsonUtil.serialize( auditRecord ) );
+                        LOGGER.trace( sessionLabel, () -> "skipping update of user history, audit record does not have a perpetratorDN: "
+                                + JsonFactory.get().serialize( auditRecord ) );
                     }
                     }
                 }
                 }
             }
             }

+ 2 - 2
server/src/main/java/password/pwm/svc/event/AuditServiceClient.java

@@ -26,7 +26,7 @@ import password.pwm.bean.SessionLabel;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmRequest;
 import password.pwm.ldap.UserInfo;
 import password.pwm.ldap.UserInfo;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
 
 
@@ -53,7 +53,7 @@ public class AuditServiceClient
             catch ( final PwmUnrecoverableException e )
             catch ( final PwmUnrecoverableException e )
             {
             {
                 LOGGER.error( sessionLabel, () -> "unexpected error submitting audit event: '"
                 LOGGER.error( sessionLabel, () -> "unexpected error submitting audit event: '"
-                        + JsonUtil.serialize( auditRecord ) + "' , error: " + e.getMessage(), e );
+                        + JsonFactory.get().serialize( auditRecord ) + "' , error: " + e.getMessage(), e );
             }
             }
         }
         }
     }
     }

+ 3 - 3
server/src/main/java/password/pwm/svc/event/CEFAuditFormatter.java

@@ -30,7 +30,7 @@ import password.pwm.config.AppConfig;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.macro.MacroRequest;
@@ -96,8 +96,8 @@ public class CEFAuditFormatter implements AuditFormatter
     {
     {
         final AppConfig domainConfig = pwmApplication.getConfig();
         final AppConfig domainConfig = pwmApplication.getConfig();
         final Settings settings = Settings.fromConfiguration( domainConfig );
         final Settings settings = Settings.fromConfiguration( domainConfig );
-        final String auditRecordAsJson = JsonUtil.serialize( auditRecord );
-        final Map<String, Object> auditRecordMap = JsonUtil.deserializeMap( auditRecordAsJson );
+        final String auditRecordAsJson = JsonFactory.get().serialize( auditRecord );
+        final Map<String, Object> auditRecordMap = JsonFactory.get().deserializeMap( auditRecordAsJson );
 
 
         final Optional<String> srcHost = PwmApplication.deriveLocalServerHostname( pwmApplication.getConfig() );
         final Optional<String> srcHost = PwmApplication.deriveLocalServerHostname( pwmApplication.getConfig() );
 
 

+ 4 - 4
server/src/main/java/password/pwm/svc/event/JsonAuditFormatter.java

@@ -25,7 +25,7 @@ import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.PwmConstants;
 import password.pwm.config.AppConfig;
 import password.pwm.config.AppConfig;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.java.JsonUtil;
+import password.pwm.util.json.JsonFactory;
 
 
 public class JsonAuditFormatter implements AuditFormatter
 public class JsonAuditFormatter implements AuditFormatter
 {
 {
@@ -43,7 +43,7 @@ public class JsonAuditFormatter implements AuditFormatter
         message.append( PwmConstants.PWM_APP_NAME );
         message.append( PwmConstants.PWM_APP_NAME );
         message.append( " " );
         message.append( " " );
 
 
-        jsonValue = JsonUtil.serialize( auditRecord );
+        jsonValue = JsonFactory.get().serialize( auditRecord );
 
 
         if ( message.length() + jsonValue.length() <= maxLength )
         if ( message.length() + jsonValue.length() <= maxLength )
         {
         {
@@ -61,7 +61,7 @@ public class JsonAuditFormatter implements AuditFormatter
             copiedRecord.message( "" );
             copiedRecord.message( "" );
             copiedRecord.narrative( "" );
             copiedRecord.narrative( "" );
             final int shortenedMessageLength = message.length()
             final int shortenedMessageLength = message.length()
-                    + JsonUtil.serialize( copiedRecord.build() ).length()
+                    + JsonFactory.get().serialize( copiedRecord.build() ).length()
                     + truncateMessage.length();
                     + truncateMessage.length();
             final int maxMessageAndNarrativeLength = maxLength - ( shortenedMessageLength + ( truncateMessage.length() * 2 ) );
             final int maxMessageAndNarrativeLength = maxLength - ( shortenedMessageLength + ( truncateMessage.length() * 2 ) );
             int maxMessageLength = inputRecord.getMessage().length();
             int maxMessageLength = inputRecord.getMessage().length();
@@ -85,7 +85,7 @@ public class JsonAuditFormatter implements AuditFormatter
                     ? inputRecord.getNarrative().substring( 0, maxNarrativeLength ) + truncateMessage
                     ? inputRecord.getNarrative().substring( 0, maxNarrativeLength ) + truncateMessage
                     : inputRecord.getNarrative() );
                     : inputRecord.getNarrative() );
 
 
-            message.append( JsonUtil.serialize( copiedRecord.build() ) );
+            message.append( JsonFactory.get().serialize( copiedRecord.build() ) );
         }
         }
 
 
         return message.toString();
         return message.toString();

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov