使用ByteBuddy,我可以通过调用另一个实例并转换结果来实现一个实例方法吗?
例如(玩具示例):
public abstract class Foo {
public String bar() {
return "bar";
}
public abstract int baz();
}
鉴于上述情况,我可以实现baz
,使其调用bar()
并返回返回字符串的长度吗?即,好像它是:
public int baz() {
return bar().length();
}
天真地,我尝试了以下内容:
Method bar = Foo.class.getDeclaredMethod("bar");
Method baz = Foo.class.getDeclaredMethod("baz");
Method length = String.class.getDeclaredMethod("length");
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(ElementMatchers.is(baz))
.intercept(
MethodCall.invoke(bar) // call bar()...
.andThen(MethodCall.invoke(length)) // ... .length()?
).make()
.load(Foo.class.getClassLoader())
.getLoaded()
.newInstance();
System.out.println(foo.baz());
但是,我认为在第一次调用的返回值上调用andThen()
时我错了;它看起来像是在生成的实例上调用的。
Exception in thread "main" java.lang.IllegalStateException:
Cannot invoke public int java.lang.String.length() on class Foo$ByteBuddy$sVgjXXp9
at net.bytebuddy.implementation.MethodCall$MethodInvoker$ForContextualInvocation
.invoke(MethodCall.java:1667)
我也试过拦截器:
class BazInterceptor {
public static int barLength(@This Foo foo) {
String bar = foo.bar();
return bar.length();
}
}
使用:
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(ElementMatchers.is(baz))
.intercept(MethodDelegation.to(new BazInterceptor()))
// ...etc.
这已经运行了,但产生了无意义的结果870698190
,并且在barLength()
中设置断点和/或添加打印语句表示它永远不会被调用;很明显,我也不能正确理解拦截器或@This
。
如何让ByteBuddy调用一个方法,然后在其返回值上调用另一个方法?
每k5_'s answer:BazInterceptor
如果 则有效:
new BazInterceptor()
,但将barLength()
作为实例方法,或者:barLength()
类方法,但委托给BazInterceptor.class
而不是实例。我怀疑870698190
已委托给hashCode()
个BazInterceptor
个实例,但我实际上没有检查过。
答案 0 :(得分:1)
您使用实例作为拦截器,这意味着首选实例方法(可能根本不接受静态方法)。有一种与int baz()
方法的签名匹配的实例方法,它是int hashCode()
。您获得的数字是new BazInterceptor()
实例的哈希码。
我知道的选项:
static
移除barLength
,以便它实际用于拦截。.intercept(MethodDelegation.to(BazInterceptor.class))
我更喜欢第二个选项,因为您没有使用BazInterceptor
实例的任何字段/状态。
答案 1 :(得分:1)
目前在Byte Buddy中没有一个好方法,但这是一个很容易添加的功能。你可以track the progress on GitHub。我会在找到一些时间后添加它。
如果要在今天实现此类链式调用,可以使用Java代码实现它们,并使用var request = require("request")
var Hapi = require('hapi');
var Slack = require('slack-node');
var h = 0;
var s = 0;
var e = 0;
function onlineBooking(){
request({
url: "http://example.com",
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
// 'if/else' checks that it receives an up respsose four times in a row
// the variable e is increased by .25 for every 200(ok response) until e reaches 1
// it will then send a message that the server is up
if(e < 1 && response.statusCode === 200){
setTimeout(function () {
console.log(response.statusCode) // Print the response code
e =e+0.25;
}, 6000); // 6 seconds delay between each response
}
else {
while(h == 0){
console.log(response.statusCode) // Print the response code
console.log("********************")
slackReviewBot("Website :robot_face: ", response.statusCode + " - OK", "http://example.com", "");
h++;
s = 0;
}
}// end of else
}// end of if
else {
console.log(response.statusCode) // Print the response code
e = 0;
setTimeout(function () {
while(s == 0){
console.log(response.statusCode) // Print the response code
console.log("********************")
slackReviewBot("Website :robot_face: ", response.statusCode, "http://example.com", "");
s++;
h=0;
}}, 3000);
} // end of else
})
}
// sets the loop for checking every 7 seconds
setInterval(function(){
onlineBooking();
}, 7000);
// this function sends server name, a message and url to slack
function slackReviewBot(servername, body, urls, bod) {
var time = require('time');
// Create a new Date instance
var now = new time.Date();
now.setTimezone("Europe/London");
var bo = body;
var bod = bod;
var urls = urls;
var sname = servername;
// you'll need to replace the slack webhook below
// you'll find info on webhooks here https://api.slack.com/incoming-webhooks
var webhook_url = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxx';
slack = new Slack();
slack.setWebhook(webhook_url);
slack.webhook({
channel: "#server-uptime",
username: "Server:",
icon_emoji: "http://4.bp.blogspot.com/-mYCTaPOu-60/VK98X5CJEyI/AAAAAAAAApM/0oplbclvnUY/s1600/unnamed.png",
text: " " + "\n" +
"*" + sname + " * " + "\n" +
"Status: " + bo + "\n" +
now + "\n" +
"Check the status here: " + urls + "\n"
}, function(err, response) {
console.log(response);
});
}
// below is so you can send a test json object to the server
// http POST localhost:1337/jsonpost test=Test
// you'll get a slack message letting you know the server is running
var server = new Hapi.Server();
server.connection({
port: 1337
});
exports.add = function(i, j) {
return i + j;
};
// Slack function for sending the test reply
function slackReviewBot2(testserver) {
testserver = testserver;
// you'll need to replace the slack webhook below
// you'll find info on webhooks here https://api.slack.com/incoming-webhooks
var webhook_url = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxx';
slack2 = new Slack();
slack2.setWebhook(webhook_url);
slack.webhook({
channel: "#server-uptime",
username: "Server-Test-Reply:",
icon_emoji: "http://www.wonderfulwebsites.ie/logo.png",
text: ":star: :star: :star: :star: :star:" + "\n" +
"\n" +
"Sever is up and running!!!"
}, function(err, response) {
console.log(response);
});
}
// take the json object for testing
server.route({
method: 'POST'
, path: '/jsonpost',
handler: function(req, reply) {
var review = {
userName: req.payload.userName
}
//passes the review to the slackbot function
slackReviewBot2(review.userName);
reply("Received");
}
});
// prints a server running message
server.start(function(){
console.log('server running at: ', server.info.url);
});
组件内联此代码。或者,您可以通过基于Advice
实例创建自己的ByteCodeAppender
来更明确地编写字节代码,但必须手动加载参数。