When you are serializing with this option:
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
Can you make exceptions for certain fields so that they still serialize (essentially overriding the options)?
Using [JsonInclude] attribute on the property (a bool type) does not work.
I tried it with a custom JsonConverter on the property but that too does not work (you never reach the Read/Write methods).
Add the following attribute to the model property:
[System.Text.Json.Serialization.JsonIgnore(Condition = JsonIgnoreCondition.Never)]
Related
I use spring-data-cassandra, and have entity like this:
#Table("users")
public class User {
#Column("permissions")
#CassandraType(type = DataType.Name.SET, typeArguments = {DataType.Name.TEXT})
public Set<String> permissions = new HashSet<>();
}
In cassandra I have table users with field permissions of type Set. It works fine when I store some values in the set, but when I try to store empty set, it becomes null when I read such entity from the repository.
Is there a way to force spring-data-cassandra to change null to empty HashSet? Or can I somehow add custom reader for this specific property of the entity?
TL;DR;
That's Cassandra's default behavior to return null for empty Collection and Map-typed columns.
Further Read
Cassandra returns null values for lists, sets, and maps, which do not contain any items. This is especially unfortunate when using classes with pre-initialized fields as seen in your question. There's an open ticket (DATACASS-266 - Loading empty collection-typed properties overwrites pre-initialized fields) in the issue tracker - as of now, without comments or votes.
We're not exactly sure whether it's a good idea to skip setting properties or apply some sort of defaulting when dealing with empty (null) collections as this raises follow-up questions what to do when:
Creating an instance through constructor creation: A value is required in such case. For property access, we could omit to set the property, for constructor creation we must provide a value.
The pre-initialized collection contains items but the one received from Cassandra is null.
We assume, the change would be applied, what will happen with already existing code that assumes empty collections default to null.
A possibility to address this behavior could be configuration on MappingCassandraConverter or an extension point to override so users can apply their own empty collection behavior.
I've been trying to eliminate the null collections in my model objects as well, and while it may not be possible to do that at the Spring Data level currently (version 2.1.x), there are some options you can consider:
Use property access for the field in question (i.e. use the annotation #AccessType(PROPERTY)), and in the setter method, set the field to an empty collection when the argument is null.
Define a compatible (see below) constructor that sets the field to an empty collection when a null is provided (and if the model is mutable, you may still want to provide the setter as above).
There are some caveats to ensure Spring Data Cassandra uses the desired constructor (e.g. don't provide a no argument constructor), so it's critical to review the "Object Mapping Fundamentals" section of the reference guide (https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#mapping.fundamentals).
Among the recommendations in that reference guide (as of version 2.1 at least) is to use an all argument constructor and make model objects immutable, which would work well with the constructor-based approach to handling nulls. Though it does mean writing and maintaining the constructor to handle the nulls rather than relying on Lombok's #AllArgsConstructor.
I have used the property access approach in one case, but not the constructor approach. However I do intend go the constructor route when adding new or model classes (I'm a fan of immutable objects, and will explore that route even without any collection fields)
I believe Spring Data Cassandra 2.0 also added persistence lifecycle callbacks which is another possible option I suppose, but I ruled that out, mainly because the logic would not reside in the model class itself (as well as going against the recommendations from the creators of the framework)
I would like to determine whether an entity property is required or not.
Does anyone know how to access all of the constraints for a given entity property?
I want to check if the NotBlank constraint is active for a certain propery.
information:
You can check the mapping information for a class (or object) with the help of the service:
validator.mapping.class_metadata_factory
The underlying class is:
Symfony\Component\Validator\Mapping\ClassMetadataFactory
The service provides a method getMetadataFor() that allows you to obtain the active mapping metadata for a class (or object).
This method returns an instance of...
Symfony\Component\Validator\Mapping\ClassMetadata
... that provides a getPropertyMetadata(string $property) method that returns the Metadata for a given property name.
example usage:
Inside a controller (or any other ContainerAware instance) you can do:
$factory = $this->container->get('validator.mapping.class_metadata_factory');
$classMetadata = $factory->getMetadataFor('Your\Bundle\Entity\Name');
$propertyMetadata = $classMetadata->getPropertyMetadata('propertyName');
View the list of Supported Validation Constraints Reference from Symfony web site
You can try ladybug bundle. It is very easy to use and shows in detail and nicely to see all properties and info inside an object.
I've learned how to create a custom ModelBinder that successfully changes the way the properties are set as parameters of my controller actions.
Now how do I intervene the inverse way? changing the way it sets the property back from the model to the View in the EditorFor method?
You can use Default Templates.
This is basically a snippet of code that is used for the type. It needs to be in the Views\Shared\DisplayTemplates and Views\Shared\EditorTemplates.
Name of the view needs to be name of the Class.
This way you may change DateTime and other basic types as well.
I'm using ASP.NET MVC3 and i'm wondering that the default modelbinder binds to public properties but not to public fields.
Normally i just define the model classes with properties but sometimes i use some predefined classes which contains some fields. And everytime i have to debug and remember that the modelbinder just don't like fields.
The question: Whats the reason behind it?
but sometimes i use some predefined classes which contains some fields
While I cannot answer your question about the exact reason why the default model binder works only with properties (my guess is that it respects better encapsulation this way and avoids modifying internal state of the object which is what fields represent) I can say that what you call predefined classes should normally be view models. You should always use view models to and from your controller actions. Those view models are classes that are specifically defined to meet the requirements of the given view.
So back to the main point: fields are supposed to be modified only from within the given class. They should not be accessed directly from the outside. They represent and hold internal state of the class. Properties on the other hand is what should be exposed to the outside world. Imagine that in the property getter/setter you had some custom logic. By modifying directly the field this custom logic would be broken and potentially bring the object into an inconsistent state.
Maybe the reason for ignoring fields is to increase performance of the binder. Instead of searching all the Fields and properties. The Model Binder search for Properties only.
Though I think the Model Binder use cache to improve performance.
DefaultModelBinder exposes a public method:
DefaultModelBinder.BindModel, and a number of protected method available for overriding. All of them listed here.
Besides the model, these method refer to properties only, not fields, like
GetModelProperties,
GetFilteredModelProperties,
GetPropertyValue,
OnXYZValidating,
OnXYZValidated,
OnXYZUpdating,
OnXYZUpdated,
GetXYZValue,
where XYZ stands for either Model, or Property/ies, or both, and so on.
As you can see there is no Fields mentioned with these names whatsoever. As Darin explained no direct changes to Model's state are tolerated by the Binder. Hence no Field in its methods.
And also, you may wish to take a look at another important class: ModelBindingContext. An instance of this class gets passed to the BindModel, and subsequently to BindSimpleModel, and BindComplexModel, depending on model type (string, int,... are considered simple, everything else is complex).
So, this context has the following properties:
ModelXYZ, and
PropertyXYZ.
In other words you have no means to reference the fields in your ViewModel unless you do not override these classes and undertake special actions to do so.
But again, beware of fighting the framework, its always easier to follow it instead.
EDIT: The ModelMetadata class holds all the data needed to bind the model. Its code however, shows no sign of fields, field names, etc. Only properties are referenced and accessed. So, even if you try to inherit and override DefaultModelBinder and ModelBinderContext, you still won't be able to access fiellds, nevermind what their access modifier is: public, private, etc.
Hope this explains most of it.
What's the point of binding the value of a NSProgressIndicator to your controller? It never seems to ask the controller for the value, except on startup. The only way to move the NSProgressIndicator seems to be by sending it #increaseBy:, which bypasses my binding. So, why would I bind?!
If your UI's bound value not updating, that means you either bungled the binding or your controller code is not modifying the bound value in a key-value-observing–compliant way. The most common problem is doing fooIvar = val rather than [self setFooIvar:val] or self.fooIvar = val.
Apple's answer to your problem:
[What to do if] Changing the value of a model property programmatically is not reflected in the user interface
If changes made to a model value programmatically are not being reflected in the user interface, this typically indicates that the model object is not key-value-observing compliant for the property, or that you are modifying the value in a manner that is bypassing key-value observing. You should ensure that:
The model class has automatic key-value observing enabled or implements manual key-value observing for the property.
That you are changing the value using an accessor method, or using a key-value-coding compliant method. Changing the value of an instance variable directly does not provide key-value observing change notifications.
If your model property is a collection, that you're modifying the content in a key-value-observing compliant manner. See “My collection controller isn’t displaying the current data” for more information.
For that answer and answers other common problems, see "Troubleshooting Cocoa Bindings."
You should also look at the examples provided by mmalc. They are a valuable resource.