Skip to content

Settings deserialization fails if FilterParams.CurrentColumnizer can't be deserialized #470

Description

@AndisGrossteins

This is the issue I already mentioned in #468.

Settings deserialization fails to instantiate FilterParams.CurrentColumnizer property from JSON path FilterParams.CurrentColumnizer.Text which is "Default (single line)" in the settings.json file.

Exception text from log file (version 1.20.0):

LogExpert.Config.ConfigManager|Error while deserializing config data: Newtonsoft.Json.JsonSerializationException: Could not create an instance of type LogExpert.ILogLineColumnizer. Type is an interface or abstract class and cannot be instantiated. Path 'FilterParams.CurrentColumnizer.Text', line 1, position 9424.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at LogExpert.Config.ConfigManager.LoadOrCreateNew(FileInfo fileInfo)

The cause of the issue is [JsonIgnore] attribute on FilterParams.CurrentColumnizer which is from System.Text.Json.Serialization but settings serialization is done with Newtonsoft.Json so the attribute is ignored when serializing. Changing the using statement in FilterParams.cs from System.Text.Json.Serialization to Newtonsoft.Json fixes the issue but the CurrentColumnizer setting is lost.

There are multiple other settings object properties with [field: NonSerialized] attribute set which must be a leftover from when settings were serialized into binary format. These might be replaced by [JsonIgnore] but I'd like some input regarding this from current project maintainers.

Activity

  1. Hirogen commented on Sep 27, 2025

    @Hirogen
    Member

    I'll have a look seems to be a bug.

    This will be part of the rework that the persister now uses json instead of xml.

    if you want, you can get the latest version from the branch persister_in_json but it currently does not build, because the implementation is not finished yet

  2. self-assigned this
    on Sep 27, 2025
  3. added
    bugPesky little gritter, needs squashing
    on Sep 27, 2025
  4. added theissue type on Sep 27, 2025
  5. AndisGrossteins commented on Sep 27, 2025

    @AndisGrossteins
    ContributorAuthor

    Yes, I'm already looking at the branch. Introducing a custom attribute and converter for serializing columnizers seems smart and more robust.

    I was pondering a simpler approach using Json.NET error handling event in ConfigManager just to avoid losing all the settings in case one entry can't be deserialized.

    Also, don't know why the [field: NonSerialized] property is ignored by Json.NET because documentation on newtonsoft.com says the System.NonSerializedAttribute is supported.

  6. Hirogen commented on Sep 27, 2025

    @Hirogen
    Member

    JSON.net and newtonsoft json are 2 different implementations of the json format. JSON.net does not support everything that newtonsoft does. thats why I use the newtonsoft one

    I would like to use the .net one, because it's a native implementation, but it's just not there yet

  7. AndisGrossteins commented on Sep 27, 2025

    @AndisGrossteins
    ContributorAuthor

    JSON.net and newtonsoft json are 2 different implementations of the json format. JSON.net does not support everything that newtonsoft does. thats why I use the newtonsoft one

    Wait, isn't Newtonsoft.Json on GitHub and Json.NET project the same thing? It certainly looks like it is one projet because the website links to the GitHub repo and repo links back to documentation. I guess the only confusion is that project is called Json.NET but repo and namespace is Newtonsoft.Json.

  8. Hirogen commented on Sep 28, 2025

    @Hirogen
    Member

    could be that I'm confusing this now with System.Text.Json 😅

  9. linked a pull request that will close this issuePersister in json #472on Sep 29, 2025
  10. Hirogen commented on Sep 29, 2025

    @Hirogen
    Member

    this should now work, the snap shot can be downloaded here as artifact https://github.com/LogExperts/LogExpert/actions/runs/18108950348

  11. AndisGrossteins commented on Sep 30, 2025

    @AndisGrossteins
    ContributorAuthor

    I'm getting an unhandled exception (in a message box) when loading a file with existing XML persistence file and after clicking on "Column restrict" checkbox:

    NullReferenceException
       at LogExpert.UI.Controls.LogWindow.LogWindow.IsFilterSearchDirty(FilterParams filterParams) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4633
       at LogExpert.UI.Controls.LogWindow.LogWindow.CheckForFilterDirty() in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4618
       at LogExpert.UI.Controls.LogWindow.LogWindow.OnColumnRestrictCheckBoxCheckedChanged(Object sender, EventArgs e) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 1485
       at System.Windows.Forms.CheckBox.set_CheckState(CheckState value)
       at System.Windows.Forms.CheckBox.OnClick(EventArgs e)
       at System.Windows.Forms.CheckBox.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(HWND hWnd, MessageId msg, WPARAM wparam, LPARAM lparam)
    

    The stack trace is not logged by NLog but just this line:

    2025-09-30 22:08:33.9658|FATAL|Program|System.Threading.ThreadExceptionEventArgs
    

    And another unhandled exception when trying to interact with filter search text comboBox because filterParams.SearchText is null:

    Object reference not set to an instance of an object.\n\n
    NullReferenceException
       at LogExpert.UI.Controls.LogWindow.LogWindow.IsFilterSearchDirty(FilterParams filterParams) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4633
       at LogExpert.UI.Controls.LogWindow.LogWindow.CheckForFilterDirty() in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4618
       at LogExpert.UI.Controls.LogWindow.LogWindow.OnFilterComboBoxTextChanged(Object sender, EventArgs e) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 2042
       at System.Windows.Forms.ComboBox.OnTextChanged(EventArgs e)
       at System.Windows.Forms.ComboBox.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(HWND hWnd, MessageId msg, WPARAM wparam, LPARAM lparam)
    

    This must be related to what I wrote about broken UI when persistence loading fails in PR #472 comment.

  12. Hirogen commented on Oct 1, 2025

    @Hirogen
    Member

    I'll have a look tonight

  13. reopened this on Oct 1, 2025
  14. Hirogen commented on Oct 1, 2025

    @Hirogen
    Member

    I'm getting an unhandled exception (in a message box) when loading a file with existing XML persistence file and after clicking on "Column restrict" checkbox:

    NullReferenceException
       at LogExpert.UI.Controls.LogWindow.LogWindow.IsFilterSearchDirty(FilterParams filterParams) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4633
       at LogExpert.UI.Controls.LogWindow.LogWindow.CheckForFilterDirty() in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4618
       at LogExpert.UI.Controls.LogWindow.LogWindow.OnColumnRestrictCheckBoxCheckedChanged(Object sender, EventArgs e) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 1485
       at System.Windows.Forms.CheckBox.set_CheckState(CheckState value)
       at System.Windows.Forms.CheckBox.OnClick(EventArgs e)
       at System.Windows.Forms.CheckBox.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(HWND hWnd, MessageId msg, WPARAM wparam, LPARAM lparam)
    

    Yeah the reason is, that I don't convert the xml files, because It's unnecessary code, this change is breaking, I will write it in the changelog.

    I'll check anyway

  15. Hirogen commented on Oct 1, 2025

    @Hirogen
    Member

    I'm getting an unhandled exception (in a message box) when loading a file with existing XML persistence file and after clicking on "Column restrict" checkbox:

    NullReferenceException
       at LogExpert.UI.Controls.LogWindow.LogWindow.IsFilterSearchDirty(FilterParams filterParams) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4633
       at LogExpert.UI.Controls.LogWindow.LogWindow.CheckForFilterDirty() in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4618
       at LogExpert.UI.Controls.LogWindow.LogWindow.OnColumnRestrictCheckBoxCheckedChanged(Object sender, EventArgs e) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 1485
       at System.Windows.Forms.CheckBox.set_CheckState(CheckState value)
       at System.Windows.Forms.CheckBox.OnClick(EventArgs e)
       at System.Windows.Forms.CheckBox.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(HWND hWnd, MessageId msg, WPARAM wparam, LPARAM lparam)
    

    The stack trace is not logged by NLog but just this line:

    2025-09-30 22:08:33.9658|FATAL|Program|System.Threading.ThreadExceptionEventArgs
    

    And another unhandled exception when trying to interact with filter search text comboBox because filterParams.SearchText is null:

    Object reference not set to an instance of an object.\n\n
    NullReferenceException
       at LogExpert.UI.Controls.LogWindow.LogWindow.IsFilterSearchDirty(FilterParams filterParams) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4633
       at LogExpert.UI.Controls.LogWindow.LogWindow.CheckForFilterDirty() in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 4618
       at LogExpert.UI.Controls.LogWindow.LogWindow.OnFilterComboBoxTextChanged(Object sender, EventArgs e) in D:\a\LogExpert\LogExpert\src\LogExpert.UI\Controls\LogWindow\LogWindow.cs:line 2042
       at System.Windows.Forms.ComboBox.OnTextChanged(EventArgs e)
       at System.Windows.Forms.ComboBox.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.Callback(HWND hWnd, MessageId msg, WPARAM wparam, LPARAM lparam)
    

    This must be related to what I wrote about broken UI when persistence loading fails in PR #472 comment.

    I got both, Bookmarks should now work, also the Column Restrict should be saved and loaded (was not loaded in the json)

  16. Hirogen commented on Oct 1, 2025

    @Hirogen
    Member

    thanks for the remarks, this should be fixed, it's still a breaking changes, since its not longer saved or loaded as xml, if you find anything new, just open a new issue, I'll try to fixed them asap, depending on my time

  17. AndisGrossteins commented on Oct 1, 2025

    @AndisGrossteins
    ContributorAuthor

    Thanks for looking into this. I'll pull the changes latest from Development branch and do some tests in a bit.

    it's still a breaking changes, since its not longer saved or loaded as xml

    IMO, for backwards compatibility the XML deserialization should be kept for at least one release (e.g. till 1.30.0) so that the previously created persistence files are not lost and to save frustrating surprise for users. Of course, persistence serialization would still be done in JSON.

    I think I found the cause of of those NullReferenceExceptions. In at least one case the cause seems to be in Persister.LoadInternal() where it returns null if the persistence file doesn't exist but subsequent code tries to access members of the returned object. I don't know if you've fixed that in #474.

  18. AndisGrossteins commented on Oct 2, 2025

    @AndisGrossteins
    ContributorAuthor

    Sorry but this settings deserialization issue will still persists. At least with custom RegEx columnizer.

    On app startup, exception thrown when deserializing settings (JSON path FilterParams.CurrentColumnizer) because columnizers have not been loaded yet:

    LogExpert.Config.ConfigManager|Error while deserializing config data: Newtonsoft.Json.JsonSerializationException: Columnizer type 'Apache error log' not found.
       at LogExpert.Core.Classes.Persister.ColumnizerJsonConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in C:\Development\LogExpert\src\LogExpert.Core\Classes\Persister\ColumnizerJsonConverter.cs:line 67
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
       at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
       at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
       at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
       at LogExpert.Config.ConfigManager.LoadOrCreateNew(FileInfo fileInfo) in C:\Development\LogExpert\src\LogExpert\Config\ConfigManager.cs:line 186
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugPesky little gritter, needs squashing

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions