In order to schedule the execution of a job, i get the name of a class as a string-input.
This class may be in one of two packages, but i don't know which one so i have to check this.
By now, i have two try-catch-blocks
Class<Job> clazz;
String className; //the above mentioned string, will be initialized
try {
clazz = (Class<Job>) Class.forName("package.one." + className);
} catch (ClassNotFoundException ex) {
try {
clazz = (Class<Job>) Class.forName("package.two." + className);
} catch (ClassNotFoundException ex1) {
//some error handling code here, as the class is
//in neither of the two packages
}
}
For more packages this will get uglier and more unreadable. Furthermore, it is - for me - against the concept of exceptions, as exceptions should'nt be expected/used for flow-control!
Is there any way to rewrite this without the utilization of the ClassNotFoundException?
I'd stick to the Class.forName method for that.
You can store the class and package names in Collections or Sets and loop through those elements. When you get a ClassNotFoundException, you just continue your search. If you don't get an exception, you exit the loop using break, as you have found the class you were looking for.
The reason I'd go for Class.forName is that it loads the class for you if it had not been already loaded by the VM. This is quite a powerful side effect.
It basically relieves you of the trouble of digging through the whole CLASSPATH and looking for class files to load in the VM and dealing with issues such as whether the class has already been loaded or not by the VM.
EDIT:
Jakob Jenkov has written some really great articles/tutorials on Java. I've found them extremely useful when dealing with reflection, class loaders and concurrency (some of the "hardest" aspects of Java).
Here's a good article on the Java class loader by him, for if you still decide not to use Class.forName.
public Class<Job> getClass(String className) {
String packages[] = { "package.one.", "package.two." };
for (int j = 0; j < packages.length; j++) {
try {
return (Class<Job>) Class.forName(packages[j] + className);
} catch (ClassNotFoundException ex) {
System.out.println("Package "+packages[j]+" is not worked");
}
}
return null;
}
You can use Guava's Reflection utilities to get the ClassInfo of every class loaded in the classpath.
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
ClassPath classPath = ClassPath.from(classLoader);
ImmutableSet<ClassInfo> set = classPath.getTopLevelClasses();
for (ClassInfo ci : set) {
System.out.println(ci.getName());
}
In the loop you can implement your custom logic to load the class with the className you're providing.
In this case, I wouldn't worry about using the ClassNotFoundException. While in general a case can be made to not use exceptions for flow control, here it hardly counts as such.
I'd probably wrap it in a function, like so
public static String getPackageForClass(String className, String... packageNames) {
for (String packageName : packageNames) {
try {
Class.forName(packageName + className);
return packageName;
} catch (ClassNotFoundException ignored) {
}
}
return "";
}
or return the class directly, if you so wish
public static Class getPackageForClass(String className, String... packageNames) {
for (String packageName : packageNames) {
try {
return Class.forName(packageName + className);
} catch (ClassNotFoundException ignored) {
}
}
return null;
}
Related
I'm using Reflection to Mock a private method (I don't want to discuss if that makes sense or not).
Anyone know why? I'll let my testClass source code here it may help. I've tryed much of the Internet helps and ways to solve this but none have worked for me.
public class testProtexManagerProcessRequiredFile {
#Mock
ProtexManager PxManager;
#Before
public void inicializa() {
MockitoAnnotations.initMocks(this);
}
#Test
public void processRequiredFileTest() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, InstantiationException {
Method method;
try {
method = ProtexManager.class.getDeclaredMethod("processRequiredFile", File.class);
method.setAccessible(true);
File FileExample = new File();
String NameExample = "Nome";
File outputs = new File();
outputs = (File) Mockito.when(method.invoke(PxManager, FileExample,NameExample)).thenReturn(FileExample);
assertNotNull(outputs);
assertEquals(outputs, method.invoke(PxManager, FileExample,NameExample));
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Teste Concluido.");
}
}
That's the method code:
private File processRequiredFile(File file, String name) {
if (!file.exists()) {
this.message = name + " file not found at location: " + file;
this.msgResponse.addMsgList(MsgCode.FAILURE, MsgLevel.ERROR, this.message, StringUtils.EMPTY);
}
return file;
}
And thank you all for helping me in my doubts.
To answer your question,
Because you caught the NoSuchMethodException. To get a test failure you have to somehow get some exception or error during the test execution
To follow up on the comments, here's how one can test this method:
// let's assume there are getter for this.message / this.msgResponse
// and this method is in the class foo.bar.Foobar
protected File processRequiredFile(File file, String name) {
if (!file.exists()) {
this.message = name + " file not found at location: " + file;
this.msgResponse.addMsgList(MsgCode.FAILURE, MsgLevel.ERROR, this.message, StringUtils.EMPTY);
}
return file;
}
In a test class foo.bar.FoobarTest:
#Mock
private File file;
private Foobar foobar = new Foobar();
#Test
public void testWithNonExistingFile() {
Mockito.when(this.file.exists()).thenReturn(false); // this is to illustrate, you could also use some non existent file: new File("/does-not-exists.foo")
File result = this.foobar.processRequiredFile(this.file, "some name");
assertThat(result).isEqualTo(this.file);
assertThat(foobar.getMsgResponse()).isNotEmpty(); // TODO: better assertion
assertThat(foobar.getMessage()).isEqualTo( "some name file not found at location: " + this.file);
}
#Test
public void testWithExistingFile() {
Mockito.when(this.file.exists()).thenReturn(true);
File result = this.foobar.processRequiredFile(this.file, "some name");
assertThat(result).isEqualTo(this.file);
assertThat(foobar.getMsgResponse()).isEmpty();
assertThat(foobar.getMessage()).isNull();
}
The class under test (i.e. Foobar) is really tested, this uses a real instance of it and call its method. A mock is used to replace something we don't have (here it's a file to illustrate but it's usually something more complicated)
What is your actual question? Why the testcase succeeds? That's already answered in the comments. You catch the exception and essentially ignore it. If you want to see the stacktrace on STDERR and let the testcase fail, you have to initiate the failing procedure yourself, e.g by calling
throw (AssertionFailedError) new AssertionFailedError("method not found").initCause(e);
This construct looks strange but JUnit 3 (I assume you're using that given your code) doesn't come with an AssertionFailedError with a constructor allowing to pass a cause. This way you see the stacktrace in your IDE as well and will be visible in JUnit-reports created during build processes.
Or is your question why the particular method is not found? One reason can be that someClass.getDeclaredMethod only returns a result if the method is declared in that particular class. If that class has a super class inheriting this method, you have to use the superclass when calling getDeclaredMethod to get the method.
If you don't know what class actually contains a method you have to iterate over all superclasses until reaching the "end":
Class<?> clazz = ProtexManager.class;
while (clazz != null) {
try {
return clazz.getDeclaredMethod("processRequiredFile", File.class);
catch(NoSuchMethodException e) {
clazz = clazz.getSuperClass();
}
}
That code block swallows the NoSuchMethodException but I don't want to do things more complicated than necessary to illustrate the idea.
Another reason why the method is not found might be that the class in question has a method processRequiredFile(java.io.File) and not processRequiredFile(com.blackducksoftware.sdk.codecenter.deeplicense.data.File). Also you later call the method by method.invoke using three parameters (PxManager, File, String) so either your call of getDeclaredMethod is missing parameter classes or your call of invoke will later fail due to the differences between declaration of the method and passed parameters.
I am trying to load methods Customer.cypher and Customer.cypherCBC method from my class Configuration. Customer class is rendering from different environments so few environmets are having cypherCBC() and cypher() method and few are having only cypher() method.
Now i want to check if cypherCBC if not there in Customer class then load cypher() method. My function is so far;
try {
Class<?> customerClass = Class.forName("com.myapp.impl.service.Customer");
Object obj = customerClass.newInstance();
//here getting "NoSuchMethodException" exception
Method methodCBC = customerClass.getDeclaredMethod("cypherCBC", String.class); //line - 7
if(methodCBC.getName().equals("cypherCBC")){
methodCBC.invoke(obj, new String(dbshPass));
System.out.println("CYPHER_CBC: "
+ methodCBC.invoke(obj, new String(dbshPass)));
}else{
Method method = customerClass.getDeclaredMethod("cypher", String.class);
method.invoke(obj, new String(dbshPass));
System.out.println("CYPHER: " + method.invoke(obj, new String(dbshPass)));
}
}catch (Exception e){
e.printStackTrace();
}
Getting an error at line 7.
NoSuchMethodException:
com.myapp.impl.service.Customer.cypherCBC(java.lang.String)
that means for particular environment class Customer doesn't having cypherCBC() method, but ideally it should come in else part and execute cypher() method.
Class<?> client = null;
Object obj = null;
try{
client = Class.forName("com.myapp.impl.service.Client");
obj = client.newInstance();
}catch (InstantiationException ex) {
System.err.println("Not able to create Instance of Class");
} catch (IllegalAccessException ex) {
System.err.println("Not able to access Class");
} catch (ClassNotFoundException ex) {
System.err.println("Not able to find Class");
}
try {
Method methodCBC = client.getDeclaredMethod("cypherCBC", String.class);
System.out.println("CYPHER_CBC: " + methodCBC.invoke(obj, new String(dbshPass)));
}catch (NoSuchMethodException ex) {
System.err.println("Not able to find Method on class");
ex.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
That is exactly what is to be expected: getDeclaredMethod() throws that exception when no method exists that meets your specification. And you are wondering that it throws an exception if the required method is missing? Hint: better read the javadoc next time. Don't assume that something does something, but verify your assumptions!
Besides: read your code again. What is it doing? You are asking "give me the method named 'foo'". And then, your next step is to ask that method "is your name 'foo'". So even without reading javadoc, it should become clear that your logic is flawed.
As solution, you can implement a non-throwing lookup yourself, like
private Method lookupCypher(Class<?> client, String methodName) {
for (Method declaredMethod : client.getDeclardMethods()) {
if (declaredMethod.getName().equals(methodName)) {
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
if (parameterTypes.length == 1 && parameterTypes[0].equals(String.class)) {
// so declaredMethod has the given name, and takes one string as argument!
return declaredMethod;
}
}
// our search didn't reveal any matching method!
return null;
}
Using that helper method, you can rewrite your code to:
Method toInvoke = lookupCypher(client, "cypherCBC");
if (toInvoke == null) {
toInvoke = lookupCypher(client, "cypher");
}
toInvoke(obj, new String ...
Or, with the idea from hunter in mind; a much more "OO like" version:
interface CustomerCypherWrapper {
void cypher(String phrase);
}
class NewCustomerWrapper() implements CustomerCypherWrapper {
#Override
void cypher(String phrase) {
new Customer.cypherCBC(phrase);
}
}
class oldCustomerWrapper() implements CustomerCypherWrapper {
#Override
void cypher(String phrase) {
new Customer.cypher(phrase);
}
}
And your client code boils down to:
CustomerCypherWrapper wrapper =
(lookupCypher(..., "cypherCBC") == null)
? new NewCustomerWrapper()
: new OldCustomerWrapper();
wrapper.cypher();
[ I hope you notice that my version A) is easier to read and B) doesn't contain any duplicated code any more. ]
And yes, an alternative implementation of the lookup method could just go like
private Method lookupCyper(Client<?>, String methodName) {
try {
return client.getDeclaredMethod(methodName, String.class);
} catch ....
and return null;
}
... return your public cypherCBC method
But that is an "uncommon practice" in Java. In Java, we ask for permission; instead of forgiveness. Unlike other languages
if you compile the application with a Customer class which has both method,you can use reflection once to check whether the cypherCBC method available or not at runtime, then you can keep that status, you can call the method without using reflection
if(newVersion)
{
customer.cypherCBC(arg);
}
else
{
customer.cypher(arg);
}
But to write a better application,you should use two version baselines.
even though this is a small code fragment you should setup a another module to hide this Customer class and its interactions,that module should have two versions. but your main module has only single version.Now when you you deliver the application , product should be packaged with right version baseline based on compatibility for the target environment.
Although reflection works (as explained in the other answers). if you have control over the Customer class, you can try a non-reflection approach.
interface CBCCypherable {
public String cypherCBC(String pass);
}
You can now have two versions of Customer class, one that implements CBCCypherable and one that doesn't. And when you call it, it looks like this:
Customer c = new Customer();
if (c instanceof CBCCypherable) {
((CBCCypherable)c).cypherCBC(pass);
} else {
c.cypher(pass);
}
What you get with this solution is much simpler code, and as a bonus the compiler will check that you use the correct method name and parameter types. Unlike with reflection, where that's all your job, and you have to run the code to find out if something's wrong.
P.s.: I don't know if this is just sample code or you are really encrypting/hashing passwords here, but it's generally considered a bad idea to roll your own security code.
I'd like to create an URL constant, like so
public static final URL REMOTE_URL = new URL("http://example.com/");
But I can't since the constructor throw a checked exception. Right now I use
public static final URL REMOTE_URL = createUrl("http://example.com/");
private static URL createUrl(String url) {
try {
return new URL(url);
} catch (MalformedURLException error) {
throw new IllegalArgumentException(error.getMessage(), error);
}
}
But it feel like reinventing the wheel. I can't possibly be the only one who want to use a URL constant no? So I was wondering if there is third-party toolbox library (like guava or apache-commons, or something else, anything) or even better, something in standard Java that include this facilities? That would help me when we start a new project by reducing the size of our util package :) .
This complaint must have been a common one, because Java has (since 1.7) introduced the URI class. You can construct it using either of the following ways:
new URI(), which throws a checked exception
URI.create(), which throws an unchecked exception
For URIs/URLs like yours that are known to come from a safe source, you can use the URI.create() variant and not have to worry about catching the exception as you know it won't be thrown.
Unfortunately, sometimes you can't use a URI and you still need a URL. There's no standard method (that I have found so far) of converting a URI into a URL that doesn't throw a checked exception.
Since everyone else is just commenting, I will provide the answer which is that no there is no standard way to do what you want :)
Also, since you mention apache commons and google guava, I would point out that standard is not exactly the correct word to use either....maybe you want open-source, free, or just third-party.
Just throwing this one in the mix - there's a lot of stylistic variation for accomplishing the same thing, this one initializes in a static init block, but it can't be final.
public static URL g_url;
static {
try {
g_url = new URL("http://www.example.org");
} catch (Exception e) {
e.printStackTrace();
}
}
You cant extend URL because it is final, but you can create a new class, perhaps named MyURL, and have it proxy the URL methods to a private (or protected) URL member.
Here is the beginnings of such a class:
package blammo.url;
import java.net.MalformedURLException;
import java.net.URL;
public class MyURL
{
private URL containedURL;
public MyURL(final String spec)
{
try
{
containedURL = new URL(spec);
}
catch (MalformedURLException exception)
{
throw new RuntimeException(exception);
}
}
public String getAuthority()
{
return containedURL.getAuthority();
}
// required for stuff that needs a URL class.
public URL getContainedURL()
{
return containedURL;
}
}
I need to generate code and in this case annotations using suns CodeModel library. The annotations value is a Class object. However that class is not known at compile time. The solution I have now is:
JAnnotationUse oneToMany = field.annotate(OneToMany.class)
.param("targetEntity", Class.forName(className);
However this obviously requires that the according class is on the classpath. I want to avoid the user having to deal with such issues.
Of course the other option would be to generate the java source code file and manipulate it afterwards (as pure string) but that seems very messy.
Is there any way with CodeModel to use the plain string className + ".class" instead?
You can handle the case where the class it not in the classpath by catching the ClassNotFoundException:
try {
JAnnotationUse oneToMany = field.annotate(OneToMany.class)
.param("targetEntity", Class.forName(className);
} catch (ClassNotFoundException e) {
// handle the exception
}
The part where you handle the exception really depends on what you're trying to achieve, depending on the situation you might want to log the error/add another anotation/throw an exception/...
Ok. Here my solution. Use javaassist to generate the class and the according Class object at runtime. Since the end result will be
#OneToMany(targetEntity = com.foo.Bar.class)
as normal text in a java source code file, it does not matter that this generated "dummy class" is not actually equivalent to the real actual class that was referenced.
So we adjust the creation of the annotation as Guillaume indicated and catch the ClassNotfoundExeption. In the exception handler we call the generateDummyClass method that uses javaassist to create a Class object:
JAnnotationUse oneToMany = field.annotate(OneToMany.class);
//...snipped...
try {
oneToMany.param("targetEntity", Class.forName(jpaProperty.getTargetEntity()));
} catch (ClassNotFoundException ex) {
try {
Class targetEntityClass = generateDummyClass(jpaProperty.getTargetEntity());
oneToMany.param("targetEntity", targetEntityClass);
} catch (CannotCompileException compileEx) {
throw ex;
}
}
}
Method generateDummyClass that create a class object at runtime using javaassist:
private Class<?> generateDummyClass(String fullQualifedClassName)
throws IOException, CannotCompileException {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(this.getClass()));
CtClass ctClass = pool.makeClass(fullQualifedClassName);
Class<?> clazz = ctClass.toClass();
return clazz;
}
And we get a java source code file with:
#OneToMany(targetEntity = org.foo.Bar.class)
private Set<Bar> bars = new HashSet<Bar>();
Okay, so I am trying to do my network packet handling in Java using classes. For reading data from my stream I use a DataInputStream. My reading thread for my server looks like this:
public void run()
{
while(client.isActive())
{
try{
handle(is.readShort());
}catch (IOException e){
client.stop(e);
break;
}
}
}
Now I've got a method handle:
public void handle(short id) throws IOException
{
InPacket packet = null;
try {
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id);
}catch (Exception e){
e.printStackTrace();
}
if (packet!=null){
packet.handle(this);
}
else{
throw new IOException("Invalid packet");
}
}
I try to instantiate a new class using the
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id);
line.
In ClassUtils this is that function:
public static <T> T newInstance(Class<? extends T> type, String className) throws
ClassNotFoundException,
InstantiationException,
IllegalAccessException {
Class<?> clazz = Class.forName(className);
Class<? extends T> targetClass = clazz.asSubclass(type);
T result = targetClass.newInstance();
return result;
}
My problem is: when I try to get that class with only part of the name (I try to get it by "InPacket1", while the class is called "InPacket1Connect"), it can't find it. Is it possible to do this in Java, and if so how? If not, what method do you recommend for handling my network packets?
An alternative approach would be to use a map (or enum) which maps the id to the full class name.
Pulling in the stuff from the comments, ensure that this mapping class is available as a jar (or may be in the same jar which contains the implementations of the packet handlers) as your "messaging layer" jar.
Like this, maybe?
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id+"Connect");
^^^^^^^^^^
(but I may have misunderstood your question)
Why can you not create the full class name?
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id + "Connect"
You could implement the functionality you seem to be asking for - a kind of "fuzzy" classname matching - by writing your own classloader. The classloader could search some directories for class files partially matching the type.
My feeling is that this is potentially a brittle solution, there's a danger of loading unexpected classes. I prefer Nim's suggestion of explicitly having a mapping table if you can't use an algorthimic classname generator.