扩展 Groovy 脚本中的 java.lang.String。

huangapple go评论136阅读模式
英文:

extending java.lang.String in groovy script

问题

我有一个相当复杂的问题。我目前正在为一个ERP系统开发一种基于Groovy的脚本语言,该脚本语言的函数和语法基于已经存在的旧的FO语言,该语言由ERP系统使用。

因此,我使用类似于h.fieldname的调用从ERP中获取值,其中h是当前选择的数据集,而fieldname是我想要从字段中获取值的名称。
我获取的字段值例如是String类型的。现在我想要扩展我检索到的这些字符串,使用一些基于"旧"语法的函数。

// 一些示例
// 获取最后3个字符
h.fieldname >> 3
// 获取前4个字符
h.fieldname << 4
// 即使h.fieldname返回的是扩展String但不是String的东西,也应该工作
assert h.fieldname == "Foo"

更新

我尝试使用@daggett的答案,以下是我的方法:

public abstract class BaseScript extends Script implements GroovyObject {
	
	@Override
	public Object run() {
		Object o = null;
		try {
			final ExpandoMetaClass metaClass = new ExpandoMetaClass(String.class, false, true);
			
			//Closure c = { int x-> delegate[-x..-1] };
			
			//ClosureMetaMethod foo = new ClosureMetaMethod​("rightShift ", c , doCall);
			
			
			metaClass.initialize();
			
			o = runCode();
		} catch (Exception e) {
			this.onerror(e);
		} finally {
			this.always();
		}
		return o;
	}

	public abstract Object runCode();

	public Object always() {
		return null;
	}
	
	public Object onerror(Object ex) {
		if (ex instanceof Exception) {
			Exception e = (Exception) ex;
			e.printStackTrace();
		}
		return null;
	}
	
}

但老实说,我不知道如何实现它,而且我也找不到任何示例。

更新 2 和解决方案

基于@daggett的答案。

package groovy.runtime.metaclass.java.lang;

import groovy.lang.DelegatingMetaClass;
import groovy.lang.MetaClass;

public class StringMetaClass extends DelegatingMetaClass {

	public StringMetaClass(Class<?> theClass) {
		super(theClass);
	}

	public StringMetaClass(MetaClass metaClass) {
		super(metaClass);
	}

	@Override
	public Object invokeMethod(Object object, String name, Object[] args) {
		// 实现 "test" >> 3
		if (name.equals("rightShift")) {
			if (args.length == 1) {
				if (args[0] instanceof Integer) {
					String str = object.toString();
					int x = ((Integer) args[0]).intValue();
					if (str.length() > x) {
						return str.substring(str.length() - x);
					}
					return str;
				} else {
					throw new IllegalArgumentException("wrong argument type, should be integer");
				}
			} else {
				throw new IllegalArgumentException("too many arguments");
			}
		}
		// 实现 "test" << 3
		if (name.equals("leftShift")) {
			if (args.length == 1) {
				if (args[0] instanceof Integer) {
					String str = object.toString();
					int x = ((Integer) args[0]).intValue();
					if (str.length() > x) {
						return str.substring(0,x);
					}
					return str;
				} else {
					throw new IllegalArgumentException("wrong argument type, should be integer");
				}
			} else {
				throw new IllegalArgumentException("too many arguments");
			}
		}
		else {
			return super.invokeMethod(object, name, args);
		}
	}

}
英文:

i've a rather complex problem. I'am currently developing a a little groovy based script language for an ERP System. The functions and syntax of "my" script language are based on the already existing old FO language which is used by the erp system.

Therefore: I'am getting values from the ERP with calls like h.fieldname, where h the currently selected dataset is and fieldname the name of the field I want my field value from.
I get the field value e.g. of type String. What I now want is to extend these strings I retrieve with a few functions, which are based on the "old" syntax.

// some samples
// get last 3 characters 
h.fieldname &gt;&gt; 3
// get first 4 characters
h.fieldname &lt;&lt; 4
// should still work even if h.fieldname, returns something which extends String but is not a String
assert h.fieldname == &quot;Foo&quot;

UPDATE

I tried to make use of the answer of @daggett, here my approach:

public abstract class BaseScript extends Script implements GroovyObject {
	
	@Override
	public Object run() {
		Object o = null;
		try {
			final ExpandoMetaClass metaClass = new ExpandoMetaClass(String.class, false, true);
			
			//Closure c = { int x-&gt; delegate[-x..-1] };
			
			//ClosureMetaMethod foo = new ClosureMetaMethod​(&quot;rightShift &quot;, c , doCall);
			
			
			metaClass.initialize();
			
			o = runCode();
		} catch (Exception e) {
			this.onerror(e);
		} finally {
			this.always();
		}
		return o;
	}

	public abstract Object runCode();

	public Object always() {
		return null;
	}
	
	public Object onerror(Object ex) {
		if (ex instanceof Exception) {
			Exception e = (Exception) ex;
			e.printStackTrace();
		}
		return null;
	}
	
}

But honestly i've no idea how to implement it and I also can't find any example.

UPDATE 2 and solution

Based on the answer of @daggett.

package groovy.runtime.metaclass.java.lang;
import groovy.lang.DelegatingMetaClass;
import groovy.lang.MetaClass;
public class StringMetaClass extends DelegatingMetaClass {
public StringMetaClass(Class&lt;?&gt; theClass) {
super(theClass);
}
public StringMetaClass(MetaClass metaClass) {
super(metaClass);
}
@Override
public Object invokeMethod(Object object, String name, Object[] args) {
// implementiert &quot;test&quot; &gt;&gt; 3
if (name.equals(&quot;rightShift&quot;)) {
if (args.length == 1) {
if (args[0] instanceof Integer) {
String str = object.toString();
int x = ((Integer) args[0]).intValue();
if (str.length() &gt; x) {
return str.substring(str.length() - x);
}
return str;
} else {
throw new IllegalArgumentException(&quot;wrong argument type, should be integer&quot;);
}
} else {
throw new IllegalArgumentException(&quot;too many arguments&quot;);
}
}
// implementiert &quot;test&quot; &lt;&lt; 3
if (name.equals(&quot;leftShift&quot;)) {
if (args.length == 1) {
if (args[0] instanceof Integer) {
String str = object.toString();
int x = ((Integer) args[0]).intValue();
if (str.length() &gt; x) {
return str.substring(0,x);
}
return str;
} else {
throw new IllegalArgumentException(&quot;wrong argument type, should be integer&quot;);
}
} else {
throw new IllegalArgumentException(&quot;too many arguments&quot;);
}
}
else {
return super.invokeMethod(object, name, args);
}
}
}

答案1

得分: 1

你不能扩展String类,因为它是final的,然而在Groovy中,你可以通过元类(metaclass)为String类添加新的方法。

String.metaClass.rightShift = { int x-> delegate[-x..-1] }

"1234567890" >> 3

返回:

890

以同样的方式为<<实现leftShift方法。

最后一个请求(assert s1==s2)不相关,因为String是一个final类(不可扩展)。

英文:

you can't extend string class because it's final, however in groovy you can add new methods to string class with help of metaclass

String.metaClass.rightShift = { int x-&gt; delegate[-x..-1] }
&quot;1234567890&quot; &gt;&gt; 3

returns

890

in the same way implement the method leftShift for &lt;&lt;

the last request (assert s1==s2) is not relevant because String is a final class (not extendable)

huangapple
  • 本文由 发表于 2020年8月27日 17:42:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/63613280.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定