String type = "";
if("searchClientContactDetails".equalsIgnoreCase(methodName) || "getClientAndVendorOrgDeatilsById".equalsIgnoreCase(methodName)
|| "saveVenodrContact".equalsIgnoreCase(methodName) || "getSpocAndOwnerDetailsById".equalsIgnoreCase(methodName)
|| "terminateSpoc".equalsIgnoreCase(methodName)){
Object[] args = joinPoint.getArgs();
Object arg=args[0];
Class c=arg.getClass();
type=(String)c.getMethod("getResponderType").invoke(arg);
}
From the above code if my getResponderType value is in the args[0] then i am getting the required value , what if my value is present in args[1] or args[2] (using the same for multiple methods). In my code i will get the "getResponderType" value in first argument for few methods and in another methods i will be getting it in second or third argument.
It will be easier if you provide the methods declarations.
Because for
void searchClientContactDetails(String a, Integer b);
void searchClientContactDetails(Long a, String b);
your
Object[] args = joinPoint.getArgs();
Object arg=args[0];
will be return different values.
Maybe it is your problem )
You can iterate over the args looking for the method getResponderType. Once you find what you are looking for, you can break.
String type = "";
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
Class clazz = arg.getClass();
try {
Method mthd = arg.getClass().getMethod("getResponderType");
if (mthd != null) {
type = (String) clazz.getMethod(
"getResponderType").invoke(arg);
break;
}
} catch (Exception e) {
//do nothing
}
}
Related
I am trying to implement the Hive UDF with Parameter and so I am extending GenericUDF class.
The problem is my UDF works find on String Datatype however it throws error if I run on other data types. I want UDF to run regardless of data type.
Would someone please let me know what's wrong with following code.
#Description(name = "Encrypt", value = "Encrypt the Given Column", extended = "SELECT Encrypt('Hello World!', 'Key');")
public class Encrypt extends GenericUDF {
StringObjectInspector key;
StringObjectInspector col;
#Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
if (arguments.length != 2) {
throw new UDFArgumentLengthException("Encrypt only takes 2 arguments: T, String");
}
ObjectInspector keyObject = arguments[1];
ObjectInspector colObject = arguments[0];
if (!(keyObject instanceof StringObjectInspector)) {
throw new UDFArgumentException("Error: Key Type is Not String");
}
this.key = (StringObjectInspector) keyObject;
this.col = (StringObjectInspector) colObject;
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
#Override
public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
String keyString = key.getPrimitiveJavaObject(deferredObjects[1].get());
String colString = col.getPrimitiveJavaObject(deferredObjects[0].get());
return AES.encrypt(colString, keyString);
}
#Override
public String getDisplayString(String[] strings) {
return null;
}
}
Error
java.lang.ClassCastException: org.apache.hadoop.hive.serde2.objectinspector.primitive.JavaIntObjectInspector cannot be cast to org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector
I would suggest you to replace StringObjectInspector col with PrimitiveObjectInspector col and the corresponding cast this.col = (PrimitiveObjectInspector) colObject. Then there are two ways:
First is to process every possible Primitive type, like this
switch (((PrimitiveTypeInfo) colObject.getTypeInfo()).getPrimitiveCategory()) {
case BYTE:
case SHORT:
case INT:
case LONG:
case TIMESTAMP:
cast_long_type;
case FLOAT:
case DOUBLE:
cast_double_type;
case STRING:
everyting_is_fine;
case DECIMAL:
case BOOLEAN:
throw new UDFArgumentTypeException(0, "Unsupported yet");
default:
throw new UDFArgumentTypeException(0,
"Unsupported type");
}
}
Another way, is to use PrimitiveObjectInspectorUtils.getString method:
Object colObject = col.getPrimitiveJavaObject(deferredObjects[0].get());
String colString = PrimitiveObjectInspectorUtils.getString(colObject, key);
It just pseudocode like examples. Hope it helps.
Decompilled method:
private static l c(String str, String str2, String str3, String str4) {
l lVar;
k kVar = (k) m.get(str);
j jVar = (j) l.get(str);
if (kVar != null) {
lVar = new l(kVar, str2, str3);
} else if (jVar != null) {
lVar = new l(jVar, str2, str3);
} else {
lVar = new l(j.GENERIC, str2, str3);
}
lVar.a(str4);
return lVar;
}
How to use Xposed to return new l (jVar, str2, str3) with its specific values?
The beginning of the code I have is:
try {
findAndHookMethod("com.xiaomi.hm.health.ui.smartplay.h", lpparam.classLoader, "c", String.class, String.class, String.class, String.class, new XC_MethodHook() {
#Override
protected void afterHookedMethod(MethodHookParam param) {
String pkg = (String) param.args[0];
if (pkg == "com.perm.kate_new_6"){
return ???;
}
}
});
} catch (Throwable t) {
t.printStackTrace();
}
The XC_MethodHook's afterHookedMethod method needs to return void. I.e., the return of the hooked method needs be be set via setResult method of XC_MethodHook instead.
Internally it sets returnEarly to true which is checked in XposedBridge, preventing the original method code from executing, as well as any other hooks on the method.
If you just want to access whatever the method was originally going to return then getResult() should do.
If you need to return anything else, you can use reflection or Xposed's helpers (findClass) to retrieve the l, k and j classes, replicate the code if needed, create a new instance and return it via setResult. Alternatively you can use a XC_MethodReplacement hook instead as you will likely replicate its functionality anyways.
C# allows the following functionality to display a user-friendly version of enums. The type converter takes the description attribute and uses it to generate a string. Can this be done in C++/CLI? From what I'm seeing, a 'public enum class' cannot have attributes on the enum members. This means I can't define the description attribute content for each enum. How can the friendly names be defined?
[TypeConverter(typeof(EnumDescriptionConverter))]
public enum MyEnum
{
[Description("Item1")]
Item1,
[Description("Item2")]
Item2,
}
class EnumDescriptionConverter : EnumConverter
{
private Type _enumType;
public EnumDescriptionConverter(Type type)
: base(type)
{
_enumType = type;
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destType)
{
return destType == typeof(string);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType)
{
String ReturnString = "";
if (_enumType.GetCustomAttributes<FlagsAttribute>().Any())
{
foreach (var val in EnumExtensions.GetIndividualFlags((Enum)value))
{
FieldInfo fi = _enumType.GetField(Enum.GetName(_enumType, val));
DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
if (ReturnString != "")
ReturnString += " | ";
if (dna != null)
ReturnString += dna.Description;
else
ReturnString += val.ToString();
}
}
else
{
FieldInfo fi = _enumType.GetField(Enum.GetName(_enumType, value));
DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
if (ReturnString != "")
ReturnString += " | ";
if (dna != null)
ReturnString += dna.Description;
else
ReturnString += value.ToString();
}
return ReturnString;
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType)
{
return srcType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
foreach (FieldInfo fi in _enumType.GetFields())
{
DescriptionAttribute dna =
(DescriptionAttribute)Attribute.GetCustomAttribute(
fi, typeof(DescriptionAttribute));
if ((dna != null) && ((string)value == dna.Description))
return Enum.Parse(_enumType, fi.Name);
}
return Enum.Parse(_enumType, (string)value);
}
}
You've broken the cardinal rule of Stack Overflow questions: You didn't actually include real source code or the exact error message.
This code compiles just fine for me in Visual Studio 2013 in a brand new C++/CLI Console Application project:
using System::ComponentModel::DescriptionAttribute;
public enum class MyEnum
{
[Description("Item1")]
Item1,
[Description("Item2")]
Item2,
};
After researching this more, I resorted to the following type converter. It simply replaces an underscore in the enum member with a space. It can also handle flags.
ref class EnumDescriptionConverter : public System::ComponentModel::EnumConverter
{
private:
System::Type^ _enumType;
public:
EnumDescriptionConverter(System::Type^ type) : System::ComponentModel::EnumConverter(type)
{
_enumType = type;
}
bool CanConvertTo(System::ComponentModel::ITypeDescriptorContext^ context, System::Type^ destType)override
{
return destType == System::String::typeid;
}
System::Object^ ConvertTo(System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, System::Object^ value, System::Type^ destType)override
{
return value->ToString()->Replace("_", " ");
}
bool CanConvertFrom(System::ComponentModel::ITypeDescriptorContext^ context, System::Type^ srcType)override
{
return srcType == System::String::typeid;
}
System::Object^ ConvertFrom(System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, System::Object^ value)override
{
return System::Enum::Parse(_enumType, ((System::String^)value)->Replace(" ", "_")->Replace(",_", ", "));
}
};
Enums are defined like this:
[System::ComponentModel::TypeConverter(typeof(EnumDescriptionConverter))]
public enum class MyEnum
{
Item_1, // Appears as 'Item 1' when data bound or in a property grid
Item_2 // Appears as 'Item 2' when data bound or in a property grid
}
So I want to use the standard format for error messages. I don't want to specify other than default codes.
Example:
domain.property.minSize.notmet=I like purple {?}.
So I am looping through my errors:
domain.errors.fieldErrors.each {
println g.message(error: it, args: ['bunnies'])
}
This doesn't work correctly because I think the first x arguments are already defined because of the default error message, and that number changes depending on what the error is. How can I specify arguments to the standard error codes without struggling to know what number '?' should be?
So I've gone down this road, hopefully there isn't some way easier option. I am overriding the messageSource bean with my own implementation that simply adds a method:
public class MessageSource extends PluginAwareResourceBundleMessageSource implements GrailsApplicationAware, PluginManagerAware, InitializingBean {
public final String getMessage(MessageSourceResolvable resolvable, Object[] args, Locale locale)
throws NoSuchMessageException {
Object[] arguments;
if (args == null) {
arguments = resolvable.getArguments();
} else {
arguments = args;
}
String[] codes = resolvable.getCodes();
if (codes == null) {
codes = new String[0];
}
for (String code : codes) {
String msg = getMessageInternal(code, arguments, locale);
if (msg != null) {
return msg;
}
}
String defaultMessage = resolvable.getDefaultMessage();
if (defaultMessage != null) {
return renderDefaultMessage(defaultMessage, arguments, locale);
}
if (codes.length > 0) {
String fallback = getDefaultMessage(codes[0]);
if (fallback != null) {
return fallback;
}
}
throw new NoSuchMessageException(codes.length > 0 ? codes[codes.length - 1] : null, locale);
}
}
This is really almost an exact copy of one of the other methods, that I just modified to take in arguments. The problem I am having with this is that it never finds my error message, always falling back to default. msg is always null.
Edit: Just tried it with the standard method and the same is true with msg always being null.
I know it is possible to retrieve a property name or a method with a return type. But is it also possible to get a method name without a return type via LINQ expression trees?
Example: string methodname = GetMethodname(x=>x.GetUser());
---> results: "GetUser"
Absolutely - but you'll want a method signature like this:
public static string GetMethodName<T>(Expression<Action<T>> action)
(That means you'll need to specify the type argument when you call it, in order to use a lambda expression.)
Sample code:
using System;
using System.Linq.Expressions;
class Test
{
void Foo()
{
}
static void Main()
{
string method = GetMethodName<Test>(x => x.Foo());
Console.WriteLine(method);
}
static string GetMethodName<T>(Expression<Action<T>> action)
{
MethodCallExpression methodCall = action.Body as MethodCallExpression;
if (methodCall == null)
{
throw new ArgumentException("Only method calls are supported");
}
return methodCall.Method.Name;
}
}
You'll need something like this method:
public static string GetMethodName<T>(Expression<Action<T>> expression) {
if (expression.NodeType != ExpressionType.Lambda || expression.Body.NodeType != ExpressionType.Call)
return null;
MethodCallExpression methodCallExp = (MethodCallExpression) expression.Body;
return methodCallExp.Method.Name;
}
Call like this: GetMethodName<string>(s => s.ToLower()) will return "ToLower".