Hello,

After my previous post http://www.javablog.fr/documentum-bof-sbo-service-based-business-object-tbo-type-based-business-object-aspects.html, just a mini post related an error java.lang.NoSuchMethodException which occurs when the use of a SBO’s method whereas it exists. Basically in JAVA, the problem seems concern the type of POJO’s argument used between the SBO and the SBO’s client (like DCTM JOB…), the package or attributes could be different.

// ERROR CASE
try {
IDfService dfService = DfClient.getLocalClientEx().newService("com.huo.lu.business.sbo.ecm.mail.IMailSBO", session.getSessionManager());

Method method = dfService.getClass().getMethod("sendMail", com.huo.lu.business.sbo.ecm.mail.Mail.class);

method.invoke(dfService, mailMessage);

} catch (Exception e) {
throw new DfException(MessageFormat.format("MailSBO.sendMail({0}, {1})", session, mailMessage), e);
}

....Caused by: java.lang.NoSuchMethodException: com.huo.lu.business.sbo.ecm.mail.impl.MailSBO.sendMail(com.huo.lu.business.sbo.ecm.mail.Mail)
at java.lang.Class.getMethod(Class.java:1624)
... 23 more

This error doesn’t concern the presence or not of “serialVersionUID” attribute in a POJO.The Serial Version ID is used when serializing and deserializing an object. Java recognizes if the bytes you want to deserialize match the local class version. If not it will throw an exception. This is important when doing RMI or persisting object structures.

private static final long serialVersionUID = 6512673270706929264L;

However, this error occurs even with a local POJO class totally identical with the POJO class version in SBO (same package, same source), so, a simple solution is the adding of JAR containing the POJO used in SBO in the CLIENT side. Another solution is the use of class loader of remote SBO when the method is loaded/retrieved with the use of JAVA reflection for instantiation for given REMOTE POJO classes.

// #### OLD : ERROR CASE
Method method = dfService.getClass().getMethod("sendMail", com.huo.lu.business.sbo.ecm.mail.Mail.class);

// #### NEW : with use of SBO class loader
Method method = dfService.getClass().getMethod("sendMail", dfService.getClass().getClassLoader().loadClass("com.huo.lu.business.sbo.ecm.mail.Mail"));

Here, a full example using the SBO class loader and JAVA reflection.
So, the local POJO classes (InternetAddress / Mail) are NOT necessary:

package com.huo.lu.business.sbo.ecm.mail;

// ... import

public class InternetAddress {
private String label;
private String address;
public InternetAddress() {
this(null, null);
}

// .... GETTERS / SETTERS
}
package com.huo.lu.business.sbo.ecm.mail;

// ... import

public class Mail {

private InternetAddress from;
private List<InternetAddress> to;
private List<InternetAddress> cc;
private List<InternetAddress> bcc;
private String subject;
private String body;

public Mail() {
}

// .... GETTERS / SETTERS
}
IDfService dfService = DfClient.getLocalClientEx().newService("com.huo.lu.business.sbo.ecm.mail.IMailSBO", session.getSessionManager());

ClassLoader classLoaderOfRemoteService = dfService.getClass().getClassLoader();

Class<?> clazzMail = classLoaderOfRemoteService.loadClass("com.huo.lu.business.sbo.ecm.mail.Mail");

Class<?> clazzInternetAddress = classLoaderOfRemoteService.loadClass("com.huo.lu.business.sbo.ecm.mail.InternetAddress");

Mail objectMail = new Mail();
objectMail = clazzMail.newInstance();

// # setFrom(InternetAddress from)
// objectMail.setFrom(new InternetAddress(SENDER_EMAIL, SENDER_FRIENDLYNAME));
{
// InternetAddress
Constructor<?> constructorInternetAddress = clazzInternetAddress.getConstructor(new Class[] { String.class, String.class});
Object objectInternetAddress = constructorInternetAddress.newInstance(new Object[] { SENDER_EMAIL, SENDER_FRIENDLYNAME });
Method methodSetFrom = objectMail.getClass().getMethod("setFrom", clazzInternetAddress);
methodSetFrom.invoke(objectMail, objectInternetAddress);
}

// # setTo(List<InternetAddress> to)
// objectMail.setTo(emailAssignees);
{
List<Object> listOfAssigneesInternetAddress = new ArrayList<Object>();
for (Iterator<String> emailAssigneesIter = emailAssignees.iterator(); emailAssigneesIter.hasNext();) {
String emailAssigneeStr = emailAssigneesIter.next();
// InternetAddress
Constructor<?> constructorInternetAddress = clazzInternetAddress.getConstructor(new Class[] { String.class});
Object objectInternetAddress = constructorInternetAddress.newInstance(new Object[] { emailAssigneeStr });
listOfAssigneesInternetAddress.add(objectInternetAddress);
}//end-for

Method methodSetTo = objectMail.getClass().getMethod("setTo", List.class);
methodSetTo.invoke(objectMail, listOfAssigneesInternetAddress);
}

// # setSubject(String subject)
// objectMail.setSubject("SUBJECT 123");
{
Method methodSetSubject = objectMail.getClass().getMethod("setSubject", String.class);
methodSetSubject.invoke(objectMail, "SUBJECT 123");
}

// # setBody(String body)
// objectMail.setBody(createMailBody());
{
Method methodSetBody = objectMail.getClass().getMethod("setBody", String.class);
methodSetBody.invoke(objectMail, createMailBody());
}

Method method = dfService.getClass().getMethod("sendMail", clazzMail);
method.invoke(dfService, objectMail);

Best regards

Huseyin OZVEREN