X-CGP-ClamAV-Result: CLEAN X-VirusScanner: Niversoft's CGPClamav Helper v1.22.2a (ClamAV engine v0.102.2) X-Junk-Score: 0 [] X-KAS-Score: 0 [] From: "OCsite" Received: from smtp-beta-2.zoner.com ([217.198.120.71] verified) by post.selbstdenker.com (CommuniGate Pro SMTP 6.3.3) with ESMTPS id 26104525 for webobjects-dev@wocommunity.org; Sat, 03 Jul 2021 23:06:04 +0200 Received-SPF: none receiver=post.selbstdenker.com; client-ip=217.198.120.71; envelope-from=ocs@ocs.cz Received: from smtp.zoner.com (smtp.zoner.com [217.198.120.6]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp-beta-2.zoner.com (Postfix) with ESMTPS id 504CB180014F for ; Sat, 3 Jul 2021 23:05:44 +0200 (CEST) Received: from macbook-pro.ocsluj (unknown [77.240.103.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: ocs@ocs.cz) by smtp.zoner.com (Postfix) with ESMTPSA id 909A93000075 for ; Sat, 3 Jul 2021 23:05:43 +0200 (CEST) Content-Type: multipart/alternative; boundary="Apple-Mail=_1DA4C34D-746B-48C3-8F99-1E653B826E5C" Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.6\)) Subject: Re: [WO-DEV] change toString for some classes? Date: Sat, 3 Jul 2021 23:05:42 +0200 References: To: WebObjects & WOnder Development In-Reply-To: Message-Id: <90FC12C6-AE64-4E8E-B1CB-366BC936687A@ocs.cz> X-Mailer: Apple Mail (2.3608.120.23.2.6) --Apple-Mail=_1DA4C34D-746B-48C3-8F99-1E653B826E5C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Dennis, thanks a lot, but it does not work for me =E2=80=94 I keep getting javassist.CannotCompileException: by java.lang.LinkageError: loader = 'app' attempted duplicate class definition for = com.webobjects.foundation.NSTimestamp. = (com.webobjects.foundation.NSTimestamp is in unnamed module of loader = 'app') Looks like some darned pre-main magic of Groovy or my own code in some = static block or something like that touches (indirectly, for I can't = find the culprit in my sources) the class and loads it before it can be = patched. Pity. Thanks and all the best, OC > On 30 Jun 2021, at 11:56, Dennis Bliefernicht = wrote: >=20 > Hi, > =20 > is there some Wonder (or NS- or Java-level) trick to =E2=80=9Coverride=E2= =80=9D (for the original class; in ObjC I would simply swizzle the = method) toString for some classes? Namely, in my current application, I = would need that > =20 > there are some ways in Java to do this kind of thing, Javassist is = something we still use in an older codebase, there is also ByteBuddy = which tries to wrap everything in a neat API. One important thing is = that you need to do this _very_ early in your application, before the = relevant classes are loaded (because this hooks into the class loading = mechanism, once the class is loaded, you can=E2=80=99t modify it that = easily anymore). In fact we do this basically first thing in the main = method. I don=E2=80=99t have any snippets at hand for ByteBuddy, but = below is an outline, how we replaced some methods with Javassist. = Basically we prepend the method with =E2=80=9Creturn = ApplicationUtility.myReplacementMethod(this)=E2=80=9D which makes it = easy enough to just code up the replacement method as usual. > =20 > Performancewise this seems to be fine, in our case we had to replace a = .hashCode() deep in WO, because performance monitoring revealed that our = data modelling resulted in wildly bad behaviour of EO objects in = HashMaps and after the fix we got good improvements. So I assume = generally the JIT compiler will smooth out any extra redirections. > =20 > Hope that helps && Greetings > Dennis > =20 > import javassist.ClassPool; > import javassist.CtClass; > import javassist.CtConstructor; > import javassist.CtMethod; > import javassist.LoaderClassPath; > =20 > public class ApplicationUtility { > public static int myReplacementMethod(final NSTimestamp object) { > // do your magic > return "TODO"; > } > =20 > public static void patchClasses() { > try { > final ClassPool classPool =3D ClassPool.getDefault(); > classPool.appendClassPath(new = LoaderClassPath(Thread.currentThread().getContextClassLoader())); > =20 > final CtClass classToPatch =3D = classPool.get("com.webobjects.foundation.NSTimestamp"); > final CtMethod toStringMethod =3D = classToPatch.getDeclaredMethod("toString"); > toStringMethod.insertBefore("{ return " + = ApplicationUtility.class.getName() + ".myReplacementMethod(this); }"); > classToPatch.toClass(); > } catch (Exception e) { > // TODO: error handling, probably logging and exit > } > } > } > =20 > =20 > =20 > --=20 > > ----------------------------------------------------- > Dennis Bliefernicht =E2=80=A2 Head of Backend Development > T +49 40 357 3001 62 > dennis.bliefernicht@xyrality.com = > =20 > XYRALITY GmbH =E2=80=A2 Friedensallee 290 =E2=80=A2 22763 Hamburg > www.xyrality.com > Registergericht: Hamburg HRB 115332 > Gesch=C3=A4ftsf=C3=BChrer: Sven Ossenbr=C3=BCggen > ----------------------------------------------------- > =20 > =20 > ############################################################# > This message is sent to you because you are subscribed to > the mailing list >. > To unsubscribe, E-mail to: > > To switch to the DIGEST mode, E-mail to = > > To switch to the INDEX mode, E-mail to = > > Send administrative queries to = > --Apple-Mail=_1DA4C34D-746B-48C3-8F99-1E653B826E5C Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8 Dennis,

thanks a = lot, but it does not work for me =E2=80=94 I keep getting

javassist.CannotCompileException: by java.lang.LinkageError: = loader 'app' attempted duplicate class definition for = com.webobjects.foundation.NSTimestamp. = (com.webobjects.foundation.NSTimestamp is in unnamed module of loader = 'app')

Looks like some = darned pre-main magic of Groovy or my own code in some static block or = something like that touches (indirectly, for I can't find the culprit in = my sources) the class and loads it before it can be patched. = Pity.

Thanks and all the = best,
OC

On 30 Jun 2021, at 11:56, Dennis Bliefernicht = <webobjects-dev@wocommunity.org> wrote:

Hi,
 
is there = some Wonder (or NS- or Java-level) trick to =E2=80=9Coverride=E2=80=9D = (for the original class; in ObjC I would simply swizzle the = method) toString for some classes? Namely, = in my current application, I would need that
 
there are some ways in = Java to do this kind of thing, Javassist is something we still use in an = older codebase, there is also ByteBuddy which tries to wrap everything = in a  neat API. One important thing is that you need to do this _very_ early in your application, before the relevant = classes are loaded (because this hooks into the class loading mechanism, = once the class is loaded, you can=E2=80=99t modify it that easily = anymore). In fact we do this basically first thing in the main method. I don=E2=80=99t = have any snippets at hand for ByteBuddy, but below is an outline, how we = replaced some methods with Javassist. Basically we prepend the method = with =E2=80=9Creturn ApplicationUtility.myReplacementMethod(this)=E2=80=9D= which makes it easy enough to just code up the replacement method as = usual.
 
Performancewise this seems = to be fine, in our case we had to replace a .hashCode() deep in WO, = because performance monitoring revealed that our data modelling resulted = in wildly bad behaviour of EO objects in HashMaps and after the fix we = got good improvements. So I assume generally the JIT compiler will = smooth out any extra redirections.
 
Hope that helps && Greetings
Dennis
 
import = javassist.ClassPool;
import javassist.CtClass;
import = javassist.CtConstructor;
import javassist.CtMethod;
import = javassist.LoaderClassPath;
 
public class ApplicationUtility {
     public static int = myReplacementMethod(final NSTimestamp object) {
           = // do your magic
           = return "TODO";
     }
 
     public static void patchClasses() = {
           = try {
          &nb= sp;     final ClassPool classPool =3D = ClassPool.getDefault();
          &nb= sp;     classPool.appendClassPath(new = LoaderClassPath(Thread.currentThread().getContextClassLoader()));
 
          &nb= sp;     final CtClass classToPatch =3D = classPool.get("com.webobjects.foundation.NSTimestamp");
          &nb= sp;     final CtMethod toStringMethod =3D = classToPatch.getDeclaredMethod("toString");
          &nb= sp;     toStringMethod.insertBefore("{ return " + = ApplicationUtility.class.getName() + ".myReplacementMethod(this); = }");
          &nb= sp;     classToPatch.toClass();
           = } catch (Exception e) {
          &nb= sp;     // TODO: error handling, probably logging = and exit
           = }
     }
}
 
 
 
-- 
<image001.png>
-----------------------------------------------------
Dennis Bliefernicht =E2=80=A2 Head of Backend Development
T +49 40 357 3001 62
 
XYRALITY GmbH =E2=80=A2 Friedensallee 290 =E2=80=A2 = 22763 Hamburg
Registergericht: Hamburg HRB 115332
Gesch=C3=A4ftsf=C3=BChrer: Sven Ossenbr=C3=BCggen
-----------------------------------------------------
 
 
#############################################################
This message = is sent to you because you are subscribed to
 the mailing list = <webobjects-dev@wocommunity.org>.
To unsubscribe, E-mail to: <webobjects-dev-off@wocommunity.org>
To switch to the DIGEST mode, = E-mail to <webobjects-dev-digest@wocommunity.org>
To switch to the INDEX mode, = E-mail to <webobjects-dev-index@wocommunity.org>
Send administrative queries to =  <webobjects-dev-request@wocommunity.org>

= --Apple-Mail=_1DA4C34D-746B-48C3-8F99-1E653B826E5C--