#Mapping on mapstruct with List<> Of List<> - mapstruct

I've recently started to use mapstruct, while coding I stuck with a scenario. In order to solve the ambiguity between the below default methods, I'm trying to use the "qualifiedBy" on a List<
#Mapping(qualifiedBy = LineTestBO). Line => 1
List<ReturnABO> toCaptureLineItemsBOs(List<LineDTO> lineDTO);
#Named("LineTestBO")
default ReturnABO map(LineDTO lineDTO) {
if (lineDTO.getCurrency() != null && lineDTO.getNationalPermit() != null &&
lineDTO.getAmount() != null && lineDTO != null)
return this.toBO(lineDTO);
return null;
}
default returnABO toBO(LineDTO lineDTO) {
// To do here
}
But Line 1 shows the error as it needs to "target" to be specified. I'm not sure what should be the target here since Line is a collection object. Even If I don't use the #mapping the mapstuct generates the mapper implementation. I read the mapstuct documentation but could not follow much for this scenario. How the Named annotation can be used on List to explicity denote that this is name to be used ? Can someone help me? Thanks.

the target must be specified, so if your POJOs look like this
class A {
private List<ReturnABO> x;
}
class B {
private List<LineDTO> x;
}
in your mapper, you could have something like this
interface AMapper {
#Mapping(target="x", source="x", qualifiedByName = "LineTestBO")
A toA(B b);
#Named("LineTestBO")
default List<ReturnABO> lineTestBO (List<LineDTO> lines) {
return lines.stream().map(this::map).collect(Collectors.toList())
}
default ReturnABO map(LineDTO lineDTO) {
if (lineDTO.getCurrency() != null && lineDTO.getNationalPermit() != null &&
lineDTO.getAmount() != null && lineDTO != null)
return this.toBO(lineDTO);
return null;
}
}

The reason for the error is that using #Mapping on iterable mapping method doesn't make much sense.
What you are looking for is IterableMapping#qualifiedBy.
So in your case the mapper needs to look like:
#Mapper
public interface MyMapper {
#IterableMapping(qualifiedByName = "LineTestBO")
List<ReturnABO> toCaptureLineItemsBOs(List<LineDTO> lineDTO);
#Named("LineTestBO")
default ReturnABO map(LineDTO lineDTO) {
if (lineDTO.getCurrency() != null && lineDTO.getNationalPermit() != null && lineDTO.getAmount() != null && lineDTO != null) {
return this.toBO(lineDTO);
}
return null;
}
default returnABO toBO(LineDTO lineDTO) {
// To do here
}
}

Related

SpecificAvroDeserializer and "specifc.avro.reader"

I have a question about SpecificAvroDeserializer because of class name, I always assumed, SpecificAvroSerializer will produce SpecificRecord and SpecificAvroDeserializer will be able to consume it.
To my surprise, if I don't set the 'specific.avro.reader' property, SpecificAvroDeserializer tries to read byte array as GenericRecord because of the following line of code at the class "AbstractKafkaAvroDeserializer" (https://github.com/confluentinc/schema-registry/blob/master/avro-serializer/src/main/java/io/confluent/kafka/serializers/AbstractKafkaAvroDeserializer.java)..
private DatumReader getDatumReader(Schema writerSchema, Schema readerSchema) {
boolean writerSchemaIsPrimitive =
AvroSchemaUtils.getPrimitiveSchemas().values().contains(writerSchema);
// do not use SpecificDatumReader if writerSchema is a primitive
if (useSpecificAvroReader && !writerSchemaIsPrimitive) {
if (readerSchema == null) {
readerSchema = getReaderSchema(writerSchema);
}
return new SpecificDatumReader(writerSchema, readerSchema);
} else {
if (readerSchema == null) {
return new GenericDatumReader(writerSchema);
}
return new GenericDatumReader(writerSchema, readerSchema);
}
}
I thought the constructor of the SpecificAvroDeserializer should set this but it does not.. (https://github.com/confluentinc/schema-registry/blob/master/avro-serde/src/main/java/io/confluent/kafka/streams/serdes/avro/SpecificAvroDeserializer.java)
So what am I missing here?

grails 3 overriding queryForResource not working

According to Grails Web Services
I can override the method queryForResource. This way I may be able to specify nested REST resource. e.g
"/authors"(resources:'author') {
"/books"(resources:'book')
}
But the doc may be wrong. Because it uses an assigment operator = instead a comparison one ==.
Running This way I get the following error:
((id == id) && building.id) is a binary expression, but it should be a variable expression
Changing the operator from = to == I get another error
Cannot query property "params" - no such property on class clash.BuildingLevel exists
What is the correct way to define this nested REST resource?
Here is my queryForResource method:
I tried both:
#Override
protected BuildingLevel queryForResource(Serializable id) {
if (params.buildingId) {
return BuildingLevel.where {
id == id && building.id = params.buildingId
}.find()
}
}
#Override
protected BuildingLevel queryForResource(Serializable id) {
if (params.buildingId) {
return BuildingLevel.where {
id == id && building.id == params.buildingId
}.find()
}
}
I just figure it out.
The following post issues-posting-nested-resource-in-grails helped me.
The params cannot be inside the where clause. So It's necessary to create a local variable to keep the value. Like this:
#Override
protected BuildingLevel queryForResource(Serializable id) {
def myLocalVariablebuildingId = params.buildingId
if (params.buildingId) {
return BuildingLevel.where {
id == id && building.id == myLocalVariablebuildingId
}.find()
}
}

JPA 2.1 Type Converter doesn't get executed on NULL values

I'm testing the new JPA 2.1 Type Converters. I want to avoid NULL String values to be stored in a legacy database as they are not allowed. So I defined the following converter:
#Converter(autoApply=true)
public class CString implements AttributeConverter<String, String> {
#Override
public String convertToDatabaseColumn(String str) {
if( str == null || str.length() == 0 ) {
return " ";
} else {
return str;
}
}
#Override
public String convertToEntityAttribute(String str) {
if( str == null || str.length() == 0 || str.equals(" ") ) {
return null;
} else {
return str;
}
}
}
String properties should be converted to a space character if they are NULL, but the converter method's are not executed when the properties are NULL.
I'm trying hibernate-jpa-2.1-api (1.0.0.Final) and hibernate-entitymanager (4.3.6.Final).
Is there any JPA 2.1 compliant way to get around this?
UPDATE: this bug has been resolved in the latest Hibernate 5.0.0.Beta1 as part of JIRA issue HHH-8697 and will be in Hibernate 4.3.9 as soon as it is released from the 4.3.9-SNAPSHOT version
If you don't want to upgrade to the beta version, you can use a workaround: take a look at JPA/Hibernate map null which explains using the getter and setter to implement your logic.

Issue with Gwt-Radio Button

I am using same group name for two of my GWT-RadioButtons. When I click one of these, another one gets unchecked, which is good. But programmatically (when i do debug) the other radio button value is still remained as 'true' . As per my requirement it should be false. I am thinking that it is problem of GWT-RadioButton Group concept.
Does this problem of GWT - RadioButton?
The below is code snippet
indiaRadioBtn.setValue(true);
indiaRadioBtn.addClickHandler(new IndianRadioClickHandler());
othersRadioBtn.addClickHandler(new InternationalRadioClickHandler());
if (contactInfo != null) {
if (contactInfo.getPostalAddress().getCountry() != null) {
othersRadioBtn.setValue(true);
}
if (indiaRadioBtn.getValue()) {
index = -1;
for (StateOrProvince stateOrProvince : StateOrProvince.values()) {
index++;
if ((contactInfo.getPostalAddress().getState() != null)
&& contactInfo.getPostalAddress().getState().equals(stateOrProvince.name())) {
stateListBox.setSelectedIndex(index);
}
}
} else {
//some code }
class IndianRadioClickHandler implements ClickHandler {
#Override
public void onClick(ClickEvent event) {
//newOrUpdateContactInfoFormPanel.clear();
ContactInfo contactInfo = getSelectedContactInfo();
/**
* Used same panel and elements for both addresses, so clearing address for Indian.
*/
if (contactInfo != null) {
if (contactInfo.getPostalAddress().getCountry() != null
|| title.equals("Create New Address")) {
contactInfo = null;
}
}
newOrUpdateContactInfoFormPanel.add(getCompleteFormPanel(contactInfo));
}
}
if contactInfo != null then it is executing that loop, i am setting othersRadioBtn.setValue(true);
So my other radio button is should set to false according to group concept.. but it is not doing its job.

jQuery.validate error in IE

I have an MVC application which I have added custom cross-field validation. The cross-field validation isn't configured to be client-side however when I tab through my fields IE is throwing the following error "$.validator.method[...] is null or not an object" from within jquery.validate.js. I have attached the full version so I can debug what's going on and it seems to be trying to fire my "mandatoryif" custom validation below on the client-side and then throwing the error at the following line:
var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
Any ideas why it is trying to do this when the "mandatoryif" validation hasn't been added client-side?
I have also updated to the latest version as I read it could be the version of jQuery.validate but this didn't fix the issue either.
Here is my custom validation:
Attribute
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class MandatoryIfAttribute : ValidationAttribute, ICrossFieldValidationAttribute
{
public string OtherProperty { get; set; }
public bool IsValid(ControllerContext controllerContext, object model, ModelMetadata modelMetadata)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
// Find the value of the other property.
var propertyInfo = model.GetType().GetProperty(OtherProperty);
if (propertyInfo == null)
{
throw new InvalidOperationException(string.Format("Couldn't find {0} property on {1}.",
OtherProperty, model));
}
var otherValue = propertyInfo.GetGetMethod().Invoke(model, null);
if (modelMetadata.Model == null)
{
modelMetadata.Model = string.Empty;
}
if (otherValue == null)
{
otherValue = string.Empty;
}
return (String.IsNullOrEmpty(modelMetadata.Model.ToString()) && (String.IsNullOrEmpty(otherValue.ToString()) || otherValue.ToString() == "0")) || (!String.IsNullOrEmpty(modelMetadata.Model.ToString()) && String.IsNullOrEmpty(otherValue.ToString())) || (!String.IsNullOrEmpty(modelMetadata.Model.ToString()) && !String.IsNullOrEmpty(otherValue.ToString()));
}
public override bool IsValid(object value)
{
// Work done in other IsValid
return true;
}
Validator
public class MandatoryIfValidator : CrossFieldValidator<MandatoryIfAttribute>
{
public MandatoryIfValidator(ModelMetadata metadata, ControllerContext controllerContext,
MandatoryIfAttribute attribute) :
base(metadata, controllerContext, attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule
{
ValidationType = "mandatoryif",
ErrorMessage = Attribute.FormatErrorMessage(Metadata.PropertyName),
};
rule.ValidationParameters.Add("otherProperty", Attribute.OtherProperty);
return new[] { rule };
}
Appreciate any help on this.
I have managed to find the answer to my query. Because some of my custom validation was doing lookups to the db I didn't want the overhead of this being done client-side so there was no client-side code. However, I didn't realise that by adding
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MandatoryIfAttribute),
typeof(MandatoryIfValidator));
in Global.asax that it was in affect adding this client-side. Of course because there was no code to process client-side it was throwing the validaiton error.