Mapstruct - update existing bean and ignore a field - mapstruct

I am updating a bean according to documentation:
#Mapper
public interface CarMapper {
void updateCarFromDto(CarDto carDto, #MappingTarget Car car);
}
Is it possible to tell mapstruct to ignore a certain field(s) ? F.e. I don't want mapstruct to map id field from carDto to car entity, and that is what mapstruct will do if I don't define the body and skip id field mapping manually. If it's not currently possible, is there any workaround (different than own impl.) ?

Use #Mapping( target = "id", ignore = true ).

Related

mapStruct: map list to other list?

I have a list List<Payment> which I'd like to map to another list List<PaymentPlan>. These types look like this:
public class Payment {
#XmlElement(name = "Installment")
#JsonProperty("Installment")
private List<Installment> installments = new ArrayList<>();
#XmlElement(name = "OriginalAmount")
#JsonProperty("OriginalAmount")
private BigDecimal originalAmount;
//getters setters, more attributes
}
and....
public class PaymentPlan {
//(Installment in different package)
private List<Installment> installments;
#XmlElement(name = "OriginalAmount")
#JsonProperty("OriginalAmount")
private BigDecimal originalAmount;
//getters setters, more attributes
}
I expect that something like this is working...
#Mappings({
#Mapping(//other mappings...),
#Mapping(source = "payments", target = "paymentInformation.paymentPlans")
})
ResultResponse originalResponseToResultResponse(OrigResponse originalResponse);
...but I get:
Can't map property java.util.List<Payment> to java.util.List<PaymentPlan>.
Consider to declare/implement a mapping method java.util.List<PaymentPlan> map(java.util.List<Payment> value);
I don't know how to apply this information. First I though I need to declare some extra mapping (in the same mapper class) for the lists, so MapStruct knows how to map each field of the List types like this:
#Mappings({
#Mapping(source = "payment.originalAmount", target = "paymentInformation.paymentPlan.originalAmount")
})
List<PaymentPlan> paymentToPaymentPlan(List<Payment> payment);
...but I get error messages like
The type of parameter "payment" has no property named "originalAmount".
Obviously I do something completely wrong, since it sound like it does not even recognize the types of the List.
How can I basically map from one List to another similar List? Obviously I somehow need to combine different mapping strategies.
btw: I know how to do it with expression mapping, like...
#Mapping(target = "paymentPlans",expression="java(Helper.mapManually(payments))")
but I guess MapStruct can handle this by iself.
I presume you are using version 1.1.0.Final. Your extra mapping is correct, the only difference is that you need to define a mapping without the lists MapStruct will then use that to do the mapping (the example message is a bit misleading for collections).
PaymentPlan paymentToPaymentPlan(Payment payment);
You don't even need the #Mappings as they would be automatically mapped. You might also need to define methods for the Instalment (as they are in different packages).
If you switch to 1.2.0.CR2 then MapStruct can automatically generate the methods for you.

Field to be unique in OrientDB Object API in schemaless mode

When using OrientDB Object API in schemaless mode, is it possible to have a field in a POJO marked as unique?
/**
The entity
*/
public class FooEntity {
#Column(unique=true)
private String bar;
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
And this is how the entity is registered, somewhere in another location in the code:
oObjectDatabase.getEntityManager().registerEntityClasses(FooEntity.class.getName());
OrientDB mechanism to map entities does not take into account the JPA annotations, but how could the same effect be achieved?
Would it be the best solution to add the constraint programmatically to the schema after registering the entity?
To add some constraint like unique (that is done through an unique index) you need to define the property in the schema, this means that you cannot have a unique constraint and be schema-less.
And yes for the OrientDB object 2.2.x and before the best way to define unique property is doing some programmatically or scripting schema definition after you registered the entity.
Bye

OData include "Custom Properties" added to Entity Framework models via Partial Classes

I made a partial class file to add new properties to my Entity-Framework generated model.
I am using WebAPI + OData, and the $metadata doesn't list my new/custom properties, and so the JSON it returns doesn't include my new/custom properties.
For example, let's say my Entity is "Person"
"Person" has one Database property; NumSpouses; an int which is returned in $metadata like this:
<Property Name="NumSpouses" Type="Edm.Int32"/>
That's great, but I added a property like this to a separate file, with a partial class:
public partial class Person {
...
public string MarriedStatus {
get { return this.NumSpouses==0 ? "Single" : "Married"; }
}
...
}
How can I get this Property available in my OData responses?
<Property Name="MarriedStatus" Type="Edm.String"/>
Currently, if I asked for MarriedStatus in $expand (as if it were a NavigationProperty.... which it's not [I thought I'd try $expand anyway as if it magically provided custom properties]), I'd get a message like this:
{
"odata.error":{
"code":"","message":{
"lang":"en-US","value":"The query specified in the URI is not valid. Could not find a property named 'MarriedStatus' on type 'fakeDataModels.Person'."
},"innererror":{
"message":"Could not find a property named 'MarriedStatus' on type 'fakeDataModels.Person'.","type":"Microsoft.Data.OData.ODataException","stacktrace":" at ..."
}
}
}
MarriedStatus is a calculated/readonly property. The ASP.NET implementation of OData does not currently support such properties. As a workaround, add a setter that throws NotImplementedException.
public string MarriedStatus {
get { return this.NumSpouses > 0 ? "Married" : "Single"; }
set { throw new NotImplementedException(); }
}
Optionally, if you are using OData V4, you can annotate MarriedStatus to specify that it is calculated. See Yi Ding's answer to OData read-only property. But the annotation is advisory only; it does not prevent clients from attempting to set a calculated property (e.g., in a POST request).
In addition to the answer of lencharest. You should use the Ignore() function of the Entity Framework fluent API instead of the [NotMapped] attribute. Because OData looks for this attribute to ignore properties for serialization. If you use the fluent API you will not have this problem.
dbModelBuilder.Entity<TEntity>()
.Ignore(i => i.ComputedProperty);

kotlin data class + bean validation jsr 303

I'm trying to get Kotlin working with jsr 303 validation on a spring-data-rest project.
Given the following data class declarartion :
#Entity data class User(
#Id
#GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
var id: Long? = null,
#Size(min=5, max=15)
val name: String
)
The #Size annotation has no effect here, making me able to save a user with a name of 1 character.
It works well when executing the very same example but in a Java class instead of Kotlin.
This makes me think of a Kotlin problem.
Thanks in advance for you help !
You need to use Annotation use-site targets since the default for a property declared in the constructor is to target the annotation on the constructor parameter instead of the getter (which will be seen by JavaBeans compliant hosts) when there are multiple options available. Also using a data class might be inappropriate here (see note at end).
#Entity data class User(
#Id
#GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
var id: Long? = null,
#get:Size(min=5, max=15) // added annotation use-site target here
val name: String
)
The property target from the Kotlin docs may look tempting, but it can only be seen from Kotlin and not Java. Usually get does the trick, and it is not needed on the bean set.
The docs describe the process as:
If you don’t specify a use-site target, the target is chosen according to the #Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:
param
property
field
And the #Size annotation is:
#Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})
Therefore since PARAMETER is a valid target, and multiple targets are available (parameter, field, method [get/set]) it choses PARAMETER which is not what you want. Therefore for a JavaBean host to see the property it will look for the getter (properties are defined by the getter/setter and not the backing field).
In one of the Java samples, it shows:
public class Book {
private String title;
private String description;
// ...
#NotEmpty(groups={FirstLevelCheck.class, Default.class})
#Size(max=30)
public String getTitle() {
return title;
}
// ...
}
Which matches our usage of having it on the getter. If it were to be on the field like some of the validation annotations show, see the field use-site target. Or if the field must also be publicly accessible, see the #JvmField annotation in Kotlin.
NOTE: As mentioned in notes from others, you should likely consider NOT using a data class for entities if they use an auto-generated ID since it will not exist for new objects the same as for retrieved objects; and a data class will generate equals and hashCode to include all fields including the ones it should not. You can read guidance about this from the Hibernate docs.
Use the #get or #field targets for validation annotations. Annotations with the target #param(first default) and #property are not supported.
e.g:
From #NotEmpty To #field:NotEmpty
data class Student(
#field:NotEmpty #field:Size(min= 2, message = "Invalid field") var name: String? = ""
)
GL
Jayson Minard
Annotation use site targets

How to solve field wrapping in Entity Framework database-first

When I use database first, after creating the edmx file, all the conceptual models have already been generated. But I want to do some special operations on certain fields. For example, there's a field named 'price'; I want the matching property 'Price' to return double of the 'price'. How can I do that? If I modify the getter in the code, every time I update the model from database, all of the modifications go away.
What's the correct way to do this?
What you can do is create a partial class for entity which contains the Price Property and put a getter like this (A property with double price will be meaningful ),
Public partial class YourEntity{
Public float DoublePrice{
get { return Price*2;}
}
}
Or you can create a class inherited from the entity,
Public partial class Entity:YourEntity{
Public override float Price{
get { return base.Price*2;}
}
}