Passing Enum Value from Unity Configuration - dependency-injection

I am having trouble passing enum value from Unity. This is my enum
public enum MyChoice
{
Choice1 = 1,
Choice2 = 2
}
I have registered typeAlias for this Enum Type like below.
<typeAlias alias ="MyChoice" type ="SomeNamespace.MyChoice, SomeAssembly" />
So far so good. Now, I need to pass an enum value to the constructor of a class from the configuration file. I am doing it as follows:
<register type="IMyInterface" mapTo="SomeClass" name="MyClass">
<constructor>
<param name ="choice" value="MyChoice.Choice1" />
</constructor>
</register>
I get an error MyChoice.Choice1 is not a valid value for MyChoice
Any idea ?

For it to work out of the box you should use the actual value for the enum and not the name. In this case instead of "MyChoice.Choice1" you should use "1".
If you want to use the name in the configuration (despite the posted example it is almost always more meaningful to use the enum name) then you could use a type converter.
Here's an example configuration:
<typeAlias alias ="EnumConverter" type ="SomeNamespace.EnumConverter`1, SomeAssembly" />
<register type="IMyInterface" mapTo="SomeClass" name="MyClass">
<constructor>
<param name ="choice" value="Choice1" typeConverter="EnumConverter[MyChoice]" />
</constructor>
</register>
And then create the EnumConverter:
public class EnumConverter<T> : System.ComponentModel.TypeConverter where T : struct
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
T result;
if (value == null || !Enum.TryParse<T>(value.ToString(), out result))
{
throw new NotSupportedException();
}
return result;
}
}

Related

How to map an attribute of Type Object in ORIKA

I have a class OrderEntryData and inside I have an attribute which is a list of configurationInfoData (List< ConfigurationInfoData >) and inside this ConfigurationInfoData an attribute of Type Object (Object value).
This value will be sometime a date , a string or a customClass.
I am using Orika for the webServices and I am trying to settle the OrderEntryDTO class.
File : customcommerceWebServices-beans.xml
<bean class="de.hybris.platform.commercewebservicescommons.dto.order.ConfigurationInfoWsDTO">
<property name="label" type="java.lang.String" />
<property name="value" type="java.lang.Object" />
</bean>
<bean class="de.hybris.platform.commercewebservicescommons.dto.order.OrderEntryWsDTO">
<property name="configurationInfos" type="java.util.List<de.hybris.platform.commercewebservicescommons.dto.order.ConfigurationInfoWsDTO>" />
<property name="orderCode" type="java.lang.String" />
</bean>
I am testing with an Object which is an instance of AddressData.
Cause the Mapping/Conversion of the address object is working well
AddressData -> AddressDTO
the problem is (I think) Orika does not recognize the instance of the object (Object source) or the destination class (Object Target).
In the response I should have a AddressWsDTO but I get :
"de.hybris.platform.cmssmarteditwebservices.dto.AbstractPageWsDTO#54330c75"
I tried to implement a converter cause I was thinking maybe Orika don't Know how to convert an object to an AddressData (not working).
#WsDTOMapping
public class ScalpAddressConverter extends BidirectionalConverter<AddressData, Object> {
#Override
public Object convertTo(AddressData addressData, Type<Object> type, MappingContext mappingContext) {
return (Object) addressData;
}
#Override
public AddressData convertFrom(Object o, Type<AddressData> type, MappingContext mappingContext) {
return (AddressData) o;
}
}

Could not find matching constructor for: DomainObjectName(java.lang.String)

I am using command object and I have used a domain object inside my command object as given below.
class JobCommand {
List<Country> countries
String name
String age
.....
}
Country Domain is as follows:
#EqualsAndHashCode(includes="id")
class Country{
String id
String name
Date createDate
......
}
I am accessing this jobCommand object from my JobController to and also in my gsp page to set the value in my Country field.
I have a search field named Country in my gsp page and it has options of Countries like, USA, India, Iran etc.
<g:select name="countries" id="country"
from="${Country.findAll()}"
value="${jobCommand ?.countries}"
multiple="true"
optionKey="id"
optionValue="name"
/>
When I select multiple Countries, and click search button, I get the exception "Could not find matching constructor for: package.Country(java.lang.String)".
There are 2 ways to Bind Params to Command object.
1. Use bindData (http://docs.grails.org/3.1.1/ref/Controllers/bindData.html)
2. To write our own Converters. I had the same issue and I wrote my own converters.
Steps to write own converter :
create converter class with below methods:
boolean canConvert(value) {
value instanceof String
}
def convert(value) {
//your logic
}
Class<?> getTargetType() {
//your type
}
Register your converter in resources.groovy inside bean{}

Enum in Grails Domain

I'm trying to use an enum in a Grails 2.1 domain class. I'm generating the controller and views via the grails generate-all <domain class> command, and when I access the view I get the error shown below. What am I missing here?
Error
Failed to convert property value of type java.lang.String to required type
com.domain.ActionEnum for property action; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[java.lang.String] to required type [com.domain.ActionEnum] for property action:
no matching editors or conversion strategy found
Enum (in /src/groovy)
package com.domain
enum ActionEnum {
PRE_REGISTER(0), PURCHASE(2)
private final int val
public ActionEnum(int val) {
this.val = val
}
int value() { return value }
}
Domain
package com.domain
class Stat {
ActionEnum action
static mapping = {
version false
}
}
View
<g:select name="action"
from="${com.domain.ActionEnum?.values()}"
keys="${com.domain.ActionEnum.values()*.name()}" required=""
value="${xyzInstance?.action?.name()}"/>
EDIT
Now getting error Property action must be a valid number after changing the following.
View
<g:select optionKey='id' name="action"
from="${com.domain.ActionEnum?.values()}"
required=""
value="${xyzInstance?.action}"/> // I tried simply putting a number here
Enum
package com.domain
enum ActionEnum {
PRE_REGISTER(0), PURCHASE(2)
final int id
public ActionEnum(int id) {
this.id = id
}
int value() { return value }
static ActionEnum byId(int id) {
values().find { it.id == id }
}
}
Domain
package com.domain.site
class Stat {
static belongsTo = Game;
Game game
Integer action
static mapping = {
version false
}
static constraints = {
action inList: ActionEnum.values()*.id
}
String toString() {
return "${action}"
}
}
Take a look here ...
Grails Enum Mapping
Grails GORM & Enums
Also you may be hitting this as well. From the docs:
1) Enum types are now mapped using their String value rather than the ordinal value. You can revert to the old behavior by changing your mapping as follows:
static mapping = {
someEnum enumType:"ordinal"
}

ActionScript: Correctly casting a bitmap to a class

I have tree instance calling an iconFunction "getIconFromItem".
<mx:Tree dataProvider="{collection}" iconFunction="getIconFromItem" />
The getIconFromItem function is returning null even though the bitmap is not null.
public function getIconFromItem(item:Object):Class {
var result:Class = item.icon as Class ;
return result ;
}
Setting a break point on the return result line reveals that item.icon is a bitmap and result is null.
Any ideas or pointers on how to successfully cast a bitmap as class so that the bitmap is returned as an icon?
Cheers
Keith
The problem here is that item.icon is of type Bitmap, which is not extended from the type Class, but from Object. Whenever you cast to a type that is not in the object's type hierarchy, null is returned.
You want to get the class of the icon, which will be instantiated by the tree control, not the icon itself, so you should change your function to
public function getIconFromItem(item:Object):Class {
return item.icon.constructor as Class;
}
The issue was iconFunction expects a class. Each embedded image has a subclass automatically generated by the compiler. Thanks to #weltraumpirat for pointing me in the right direction :-)
The goal was to dynamically display icons in a tree class. It is possible to modify the class created by Ben Stucki (http://blog.benstucki.net/?p=42) to work with the TreeItemRenderer.data object but this failed when I created a custom MXTreeItemRenderer.
Ended up creating a BitmapImage and a custom TreeItemRenderer which used a prefined iconBitmap attribute within a class to dynamically load icons.
package components
{
import flash.display.BitmapData;
import mx.core.mx_internal;
import spark.core.IContentLoader;
import spark.primitives.BitmapImage;
public class RuntimeBitmapImage extends BitmapImage
{
public function RuntimeBitmapImage()
{
super();
}
public function set bitmapData(bitmapData:BitmapData):void
{
super.setBitmapData(bitmapData, false);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<s:MXTreeItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" >
<fx:Script>
<![CDATA[
override public function set data(value:Object):void {
super.data = value;
if ( value != null ) {
if ( value.iconBitmap != null ) {
runtimeBitmapImage.bitmapData = value.iconBitmap.bitmapData ;
}
}
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="hovered" />
<s:State name="selected" />
</s:states>
<s:HGroup left="0" right="0" top="0" bottom="0" paddingTop="2" verticalAlign="middle">
<s:Rect id="indentationSpacer" width="{treeListData.indent}" percentHeight="100" alpha="0">
<s:fill>
<s:SolidColor color="0xFFFFFF" />
</s:fill>
</s:Rect>
<potentiate:RuntimeBitmapImage id="runtimeBitmapImage" left="2" width="18" />
<s:Label id="labelField" text="{treeListData.label}" paddingTop="2"/>
</s:HGroup>
</s:MXTreeItemRenderer>

Localizing enum values in resource bundle

I have a problem with i18n enums in my JSF application. When I started, I had enums with the text defined inside. But now, I have keys tied to message bundles in the enum.
Example one of my enums:
public enum OrderStatus implements CustomEnum {
PENDING("enum.orderstatus.pending"),
CANCELED("enum.orderstatus.canceled");
/**
* key in message bundle
*/
private String name;
OrderStatus(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
In the view layer, I use something like:
<!-- input -->
<h:selectOneMenu value="#{order.status}">
<f:selectItems value="#{flowUtils.orderStatuses}"/>
</h:selectOneMenu>
<!-- output -->
<h:outputText value="#{order.status}"/>
and in Java:
public class FlowUtils {
public List<SelectItem> getOrderStatuses() {
ArrayList<SelectItem> l = new ArrayList<SelectItem>();
for(OrderStatus c: OrderStatus.values()) {
// before i18n
// l.add(new SelectItem(c, c.getName()));
// after i18n
l.add(new SelectItem(c, FacesUtil.getMessageValue(c.getName())));
}
return l;
}
}
public class FacesUtil {
public static String getMessageValue(String name) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getResourceBundle(context, "m").getString(name);
}
}
It worked well, but when I needed to output #{order.status}, I needed to convert it.
So I implemented a converter, but got in trouble with conversion of String to Object in the getAsObject() method.
web.xml:
<converter>
<converter-for-class>model.helpers.OrderStatus</converter-for-class>
<converter-class>model.helpers.EnumTypeConverter</converter-class>
</converter>
Java:
public class EnumTypeConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent comp,
String value) throws ConverterException {
// value = localized value :(
Class enumType = comp.getValueBinding("value").getType(context);
return Enum.valueOf(enumType, value);
}
#Override
public String getAsString(FacesContext context, UIComponent component,
Object object) throws ConverterException {
if (object == null) {
return null;
}
CustomEnum type = (CustomEnum) object;
ResourceBundle messages = context.getApplication().getResourceBundle(context, "m");
String text = messages.getString(type.getName());
return text;
}
}
I'm entangled now with that. Anybody know how to internationalize multiple Enums efficiently?
The value which is passed through the converter is not the option label as you seem to expect, but the option value. The best practice is to not do this in the model side, but in the view side, because the model shouldn't need to be i18n aware.
As to the approach, you're basically unnecessarily overcomplicating things. Since JSF 1.2 there's a builtin EnumConverter which will kick in automatically and since JSF 2.0 you can iterate over a generic array or List in f:selectItems by the new var attribute without the need to duplicate the values over a List<SelectItem> in the model.
Here's how the bean can look like:
public class Bean {
private OrderStatus orderStatus;
private OrderStatus[] orderStatuses = OrderStatus.values();
// ...
}
And here's how the view can look like (assuming that msg refers to the <var> as you've definied in <resource-bundle> in faces-config.xml):
<h:selectOneMenu value="#{bean.orderStatus}">
<f:selectItems value="#{bean.orderStatuses}" var="orderStatus"
itemValue="#{orderStatus}" itemLabel="#{msg[orderStatus.name]}" />
</h:selectOneMenu>
That's all.
Unrelated to the problem, you've typos in the enum name and message keys, it should be:
PENDING("enum.orderstatus.pending"),
CANCELLED("enum.orderstatus.cancelled");
And, more clean would be to keep the bundle keys out the enum and use enum itself as part of bundle key. E.g.
PENDING,
CANCELLED;
<h:selectOneMenu value="#{bean.orderStatus}">
<f:selectItems value="#{bean.orderStatuses}" var="orderStatus"
itemValue="#{orderStatus}" itemLabel="#{msg['enum.orderstatus.' += orderStatus]}" />
</h:selectOneMenu>
enum.orderstatus.PENDING = Pending
enum.orderstatus.CANCELLED = Cancelled
I have posted my solution here: Internationalization of multiple enums (translation of enum values) - but still hoping for further enhancement.
EDIT: with the help of #Joop Eggen, we have come up with a really cool solution:
EDIT again: complete and ready-to-use solution:
Make a class
public final class EnumTranslator {
public static String getMessageKey(Enum<?> e) {
return e.getClass().getSimpleName() + '.' + e.name();
}
}
Make it a custom EL function
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
version="2.0">
<namespace>http://example.com/enumi18n</namespace>
<function>
<function-name>xlate</function-name>
<function-class>your.package.EnumTranslator</function-class>
<function-signature>String getMessageKey(java.lang.Enum)</function-signature>
</function>
</facelet-taglib>
Add the taglib to your web.xml
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/enumi18n.taglib.xml</param-value>
</context-param>
Have properties files enum_en.properties and enum_yourlanguage.properties like this
TransferStatus.NOT_TRANSFERRED = Not transferred
TransferStatus.TRANSFERRED = Transferred
Add the properties files as resource bundles to your faces-config.xml
<resource-bundle>
<base-name>kk.os.obj.jsf.i18n.enum</base-name>
<var>enum</var>
</resource-bundle>
Add the custom taglib to your xhtml files
<html ... xmlns:l="http://example.com/enumi18n">
And - voilĂ  - you can now access the translated enum values in jsf:
<h:outputText value="#{enum[l:xlate(order.transferStatus)]}" />
Well, enum is just another class. There is nothing stopping you from adding parsing and to-string conversion methods that will parse and output locale-sensitive messages.
Maybe it violates Single Responsible Principle (does it?), but I believe making enum responsible for parsing and returning locale-aware values is the right thing to do.
Just add two methods like this:
public String toString(FacesContext context) {
// need to modify the method
FacesUtil.getMessageValue(context, name);
}
public OrderStatus parse(FacesContext context, String theName) {
for (OrderStatus value : values()) {
if (value.toString(context).equals(theName) {
return value;
}
}
// think of something better
return null;
}
I hope I got the code right, as I am not checking it with IDE now... Is this what you were looking for?
I calculate the message key in the enum like as shown below; so no need to maintain the keys with additional attributes on the enum
public String getMessageKey() {
return String.format("enum_%s_%s", this.getClass().getSimpleName(),
this.name());
}
Then I use it like this
<p:selectOneMenu id="type"
value="#{xyzBean.type}" required="true">
<f:selectItems
value="#{xyzBean.possibleTypes}"
var="type" itemLabel="#{msg[type.messageKey]}">
</f:selectItems>
</p:selectOneMenu>
with having configured a org.springframework.context.support.ReloadableResourceBundleMessageSource in the app context
<bean id="msg"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/resources/locale/messages" />
<property name="useCodeAsDefaultMessage" value="true" />
<property name="cacheSeconds" value="1" />
</bean>
In case anyone is looking for a simple utility library to handle enum internationalization, please take a look at https://github.com/thiagowolff/litefaces-enum-i18n
The artifact is also available in Maven Central:
<dependency>
<groupId>br.com.litecode</groupId>
<artifactId>litefaces-enum-i18n</artifactId>
<version>1.0.1</version>
</dependency>
Basically, you just need to add the artifact to your project and define the enum respective keys following the described enum naming conventions. The translations (and also CSS class names) can be retrieved using the provided EL functions.

Resources