freemarker : cast "Interface" Object to the real concret class - freemarker

I iterate to a list of IColonne object. But I need to cast to the concret class to get specific attribut. My list have "Colonne" and "ColonneGroup" object.
The IColonne interface :
public interface IColonne {
String getFtlName();
int getWidthPx(final int tableSize);
}
The Colonne concrete class:
public class Colonne implements IColonne {
....
}
The ColonneGroup concret class :
public class ColonneGroup implements IColonne {
private List<String> texts;
}
I need to access to access to the "texts" attribut. But I have "only" IColonne. So I need to cast to ColonneGroup. How can I do this?

I suppose you need to access texts from a FreeMarker template. As FTL is dynamically typed, you need no casting for that. You can just access the member, if the object has a public getTexts() method. Wether it has it (and that it's also non-null) you can test as colonne.texts??, or you can use the ! operator to give it a default. So it could be something like this:
<#list colonnes as colonne>
...
<#if colonne.texts??>
Do something with colonne.texts
</#if>
...
<#!-- Or if you would #list the texts anyway: -->
<#list colonne.texts!>
<p>We have some texts here:
<ul>
<#items as text>
<li>${text}</li>
</#items>
</ul>
</#list>
...
</#list>

Related

Unable to submit list of LocalTime in Spring

I have this entity that contains a list of objects (omitted getters and setters and all irrelevant code for this example)
public class SampleType {
#OneToMany
List<SampleTypeTime> sampleTypeTimes = new ArrayList<SampleTypeTime>();
}
public class SampleTypeTime {
#DateTimeFormat(iso = ISO.TIME)
LocalTime time;
}
And i have this form that allows the user to select multiple hours..
<form th:object="${sampleType}" th:method="POST" th:action="#{#}">
<select th:field="*{sampleTypeTimes}" type="time" class="form-control" multiple>
<option th:value="00:00" th:text="${"00:00"}"></option>
<option th:value="01:00" th:text="${"01:00"}"></option>
... and so on
</select>
</form>
My controller:
#PostMapping("sampletype/")
public String productsTypesPost(#ModelAttribute SampleType sampleType, Model model) {
sampleTypeRepository.save(sampleType);
return "sampletype";
}
When i submit the form i get the following error message:
Field error in object 'sampleType' on field 'sampleTypeTimes': rejected value [00:00,02:00];
codes [typeMismatch.sampleType.sampleTypeTimes,typeMismatch.sampleTypeTimes,typeMismatch.java.util.List,typeMismatch];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [sampleType.sampleTypeTimes,sampleTypeTimes];
arguments []; default message [sampleTypeTimes]]; default message [Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.List' for property 'sampleTypeTimes';
nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.example.project.SampleTypeTime' for property 'sampleTypeTimes[0]': no matching editors or conversion strategy found]
It seems to me that it struggles converting String[] to List, how can i get around this?
Edit: added controller class
As I said in my comment, form returns value of String while the array contains instances of SampleTypeTime. You need to tell Spring how to convert String to SampleTypeTime. For doing that you have to create implementation of PropertyEditor:
public class SampleTypeTimeEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) throws IllegalArgumentException {
LocalTime time = LocalTime.parse(text);
SampleTypeTime sampleTime = new SampleTypeTime();
sampleTime.setTime(time);
setValue(appointment);
}
}
In this example code snippet I don't check the text if it has a right format or not. But in real code you should do it of course. After that add the created property editor to the DataBinder of your controller:
#Controller
public class FormController {
#InitBinder
public void initBinder(DataBinder binder)
binder.registerCustomEditor(SampleTypeTime.class, new SampleTypeTimeEditor());
}
...
}
Now Spring automatically will convert String to SampleTypeTime. You can get more information about PropertyEditor from this chapter of the official documentation. And here you can get details about DataBinder.

spring data mongodb enum mapping converter

I would like code not throws exception when java code load enum value from mongo that not exists in enum code
Exemple :
java.lang.IllegalArgumentException: No enum constant fr.myapp.type.OrderOptionEnum.TELEPHONE
at java.lang.Enum.valueOf(Enum.java:238)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleRead(MappingMongoConverter.java:819)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readCollectionOrArray(MappingMongoConverter.java:909)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1184)
Because TELEPHONE not existe in OrderOptionEnum
I juste want the code return null value
Any idea ?
Regards
you can add a custom converter implement Converter<String, OrderOptionEnum> there you implement your own convert logic from string to your enum.
something like this
public class OrderOptionEnumMongoConverter implements Converter<String, OrderOptionEnum> {
#Override
public OrderOptionEnum convert(String source) {
for (OrderOptionEnum OrderOptionEnum : OrderOptionEnum.values()) {
if (OrderOptionEnum.name().equals(source))
return OrderOptionEnum;
}
return null;
}
}
Notice !!! This converter will try to convert each string in mongo to your enum, thus may result in unwanted conversions, so make sure you do this only when needed.
you can add #ReadingConverter if you want this convert only when reading from mongo.

How can I create "static" method for enum in Kotlin?

Kotlin already have number of "static" methods for enum class, like values and valueOf
For example I have enum
public enum class CircleType {
FIRST
SECOND
THIRD
}
How can I add static method such as random(): CircleType? Extension functions seems not for this case.
Just like with any other class, you can define a class object in an enum class:
enum class CircleType {
FIRST,
SECOND,
THIRD;
companion object {
fun random(): CircleType = FIRST // http://dilbert.com/strip/2001-10-25
}
}
Then you'll be able to call this function as CircleType.random().
EDIT: Note the commas between the enum constant entries, and the closing semicolon before the companion object. Both are now mandatory.

Generic Request Param (runtime construction)

My requests look like:
http://...
?type[A].size=14
&type[B].query=test
My #Controller has a method which should accept those generic request params:
#RequestMapping(...)
public void test(MyModel m) {
...
}
public static class MyModel {
Map<String, ?> type;
}
The problem is: ? should be some class which is defined by the key of the Map.
This means: key=A should Map to class A and key=B should map to class B. According to the given request above: Class A will have a property int size and class B will have a property String query.
I just can't figure out, how I can tell Spring to use class A for key A and class B for key B.
(I know I could do it with POST and Jackson, but I'd like to solve this using a GET request).
Thanks for your help :)

JAXB Map String to Enum Values in Generated XSD

I have a simple POJO with a String property. This String property actually contains values backed by a Java Enum. For reasons that I won't go into here, I can't just use the enum type on my POJO. Is there any JAXB annotation I can use on the String property such that when the XSD is generated, I have the values restricted to the the backing list of Enum values?
You should be able to use an XmlAdapter for this use case:
public class MyEnumAdapter extends XmlAdapter<MyEnum, String> {
...
}
Then on your class register the XmlAdapter on the String property that corresponds to the enum.
#XmlJavaTypeAdapter(MyEnumAdapter.class)
public String getValue() {
return value;
}

Resources