In the previous stack of learning, the legacy of a problem, the value stack saved some information on the action, and the page to take action from the value stack data, this process is how to achieve. The information on the page is all strings, and the types of variables in the actual run are varied and how they do the type conversions.
First we need to know that an interface in the OGNL jar package OGNL. TypeConverter, what is it doing? The implementation class for this interface is OGNL. Defaulttypeconverter is a class that implements OGNL type conversions, and it can support basic types of conversions.
So, what did Xwork do.
Let's look at a class like this, Ognltypeconverterwrapper.
public class Ognltypeconverterwrapper implements OGNL. TypeConverter {
private typeconverter typeconverter;
Public Ognltypeconverterwrapper (TypeConverter conv) {
if (CONV = = null) {
throw new IllegalArgumentException (" Wrapped type converter cannot be null ");
}
This.typeconverter = conv;
}
Public Object Convertvalue (MAP context, object target, member member,
String PropertyName, Object value, Class totype) {return
Typeconverter.convertvalue (context, Target, member, PropertyName, Value, ToType);
}
Public TypeConverter Gettarget () {return
typeconverter;
}
}
What kind of information we can get from this class. First, it's an adorner that implements OGNL. TypeConverter interface, which is for OGNL. The implementation class of the TypeConverter interface is packaged, which shields the OGNL directly. The TypeConverter implementation class, which can be converted using Xwork custom types, can also make type conversions more powerful.
Let's take a look at who called this wrapper class
The Setroot () method under Ognlvaluestack
protected void Setroot (Xworkconverter xworkconverter, compoundrootaccessor accessor, compoundroot CompoundRoot,
Boolean allowstaticmethodaccess) {
this.root = compoundroot;
this.securitymemberaccess = new Securitymemberaccess (allowstaticmethodaccess);
This.context = Ognl.createdefaultcontext (this.root, Accessor, new Ognltypeconverterwrapper (XworkConverter), securitymemberaccess);
Context.put (Value_stack, this);
Ognl.setclassresolver (context, accessor);
((ognlcontext) context). Settraceevaluations (false);
((ognlcontext) context). Setkeeplastevaluation (false);
The effect of this method is actually the initialization of the Valuestack, here you can see, actually involved in the whole process is decorated after the ognltypeconverterwrapper. In fact, we found that the operation of the value stack turned out to be an operation on the Compoundroot type root object, and the Compoundroot class inherited the ArrayList stack structure, and the root object was the object that OGNL took out of the page.
From this we know, in fact, our operations on the root object is the operation of the value stack, any object located in the Valuestack is considered as the Ognl root object in the calculation.
The basic logic of OGNL in the calculation of expression logic is to start the expression matching calculation on each stack element from the top of the stack, and return the first successful matching expression evaluation result.
Let's take a look at where Ognltypeconverterwrapper's Convertvalue () are invoked.
Implementation class
Obviously, it's all about the various types of conversions.
Because of the use of the adorner, so Xwork's TypeConverter replaces the Ognl.typeconverter, let's take a look at this interface.
Public interface TypeConverter
{public
object Convertvalue (map<string, object> context, Object target, Member member, String PropertyName, Object value, Class totype);
public static final Object no_conversion_possible = "OGNL." Noconversionpossible ";
public static final String Type_converter_context_key = "_typeconverter";
}
The default implementation of TypeConverter is the Defaulttypeconverter class, which implements the most basic type conversion mode.
Defaulttypeconverter has such two subclasses, respectively, Xworkbasicconverter and Xworkconverter.
Xworkbasicconverter class
Here we can see that the Xworkbasicconverter class provides more extensive type conversion support.
Before we talk about Xworkconverter, we'll talk about defining some data structures in Defaulttypeconverterholder.
Now let's take a look at the list of methods in Xworkconverter
Most of the methods found inside are the operations of the four HashMap in the Defaulttypeconverterholder.
These four HashMap mapping relationships receive system-level mapping cache tables, property mapping cache Tables within Java classes, and cannot find the cache sets of those Java classes that type conversion processing classes and those unknown type conversions.
From the initialization source, we can see that in the STRUTS2 framework, three different types of conversions can be supported in the declaration of processing.
Under the SRC xwork-conversion.properties statement.
Declared in the Classname-conversion.properties file in the package directory where the Java class is in.
Specify special annotations for Java classes
The Convertvalue () of the Xworkconverter class reveals the initialization and practical application of type conversions.
Public Object Convertvalue (map<string, object> context, object target, member member, String property, object value
, Class Toclass) {////Process the conversion using the default mappings, if one exists//
TypeConverter TC = NULL;
if ((value!= null) && (Toclass = = Value.getclass ())) {return value; }//Allow this is called without any context//i.e. it can is called with as little as "objec T value "and" Class Toclass if (target!= null) {//Get target clazz Class clazz = Target.getclass ()
;
object[] Classprop = null;
This is to handle weird issues and setValue with a different type///If the object is compoundroot, some processing is required if (target instanceof Compoundroot) && (context!= null) {Classprop = Getclassproperty (context)
; } if (Classprop!= null) {clazz =(Class) classprop[0];
property = (String) classprop[1];
////According to the Target's Clazz and property, find the corresponding type conversion method TC = (TypeConverter) getconverter (Clazz, property); if (log.isdebugenabled ()) Log.debug ("Field-level type converter for property [" + Property + "] =" + (TC = null?)
"None found": TC)); //If context exists, you can search for the target Clazz and property based on path if (TC = NULL && context!= NULL) {// OK, let's look if we can look it up by the path as requested in XW-297 Object Lastpropertypath = Context.get (Reflec
Tioncontextstate.current_property_path);
Class Clazz = (Class) Context.get (xworkconverter.last_bean_class_accessed);
if (Lastpropertypath!= null && clazz!= null) {String path = Lastpropertypath + "." + property;
TC = (TypeConverter) getconverter (clazz, path);
} if (TC = NULL) { if (Toclass.equals (string.class) && (value!= null) &&! ( Value.getclass (). Equals (String.class) | | Value.getclass (). Equals (String[].class))) {//when converting to a String, use the source target ' s class '
s Converter tc = lookup (Value.getclass ()); else {//when converting to a string, use the Toclass ' s converter tc = lookup (toclass
); } if (log.isdebugenabled ()) Log.debug ("Global-level type converter for property [" + Property + "] =" + (TC = null?)
None found ": TC)";
} if (TC!= null) {try {//If TypeConverter is found at this time, use that TypeConverter to complete the logic
Return Tc.convertvalue (context, target, Member, property, value, Toclass); catch (Exception e) {if (log.isdebugenabled ()) Log.debug ("Unable to convert value u Sing type converter [#0] ", E, Tc.getclass ().GetName ());
Handleconversionexception (Context, property, value, target);
return typeconverter.no_conversion_possible;
} if (Defaulttypeconverter!= null) {try {if (log.isdebugenabled ())
Log.debug ("Falling back to default type converter [" + Defaulttypeconverter + "]");
Return Defaulttypeconverter.convertvalue (context, target, Member, property, value, Toclass); catch (Exception e) {if (log.isdebugenabled ()) Log.debug ("Unable to convert value u
Sing type converter [#0] ", E, Defaulttypeconverter.getclass (). GetName ());
Handleconversionexception (Context, property, value, target);
return typeconverter.no_conversion_possible; } else {try {if (log.isdebugenabled ()) Log.debug ("Falling Back To OGNL ' s default Type CoNversion ");
return Super.convertvalue (value, Toclass); catch (Exception e) {if (log.isdebugenabled ()) Log.debug ("Unable to convert value u
Sing type converter [#0] ", E, Super.getclass (). GetName ());
Handleconversionexception (Context, property, value, target);
return typeconverter.no_conversion_possible;
}
}
}
Content selected from the "STRUTS2 Technology Insider-In-depth analysis STRUTS2 architecture design and implementation principles" I think the writing is very accurate, benefited.