Finding a class reflectively by its simple-name alone - java

I was wondering if there is any given function that allows me to introspect a class without having to write the packages where the class is contained.
For example, I want to take a look at the methods and superclasses of the class Integer in order to do that I have to specify the packages where the class is located. This will be "java.lang.Integer"
Instead of doing that I want to just type the class name in order to have the information of the class displayed. Just like this "Integer"
How can I make that my program just check the class name, no matter where is it located?

Java will not stop you from creating your own my.company.Integer class and my.other.company.Integer class, so how it cannot know which Integer class is the right one.
The closes thing to an answer I can suggest is to create a pre-defined list of packages where you want to search the class for, and keep trying each until you find your class.
So something like:
class ClassFinder{
public static final String[] searchPackages = {
"java.lang",
"java.util",
"my.company",
"my.company.other" };
public Class<?> findClassByName(String name) {
for(int i=0; i<searchPackages.length; i++){
try{
return Class.forName(searchPackages[i] + "." + name);
} catch (ClassNotFoundException e){
//not in this package, try another
} catch (...){
//deal with other problems...
}
}
//nothing found: return null or throw ClassNotFoundException
return null;
}
}
If you want to get a list of all available packages instead of hard-coding them, see here.
Be warned that this method is unlikely to perform very well, so use it sparingly.

Borrowed code, slightly modified (...from #rodion's answer)
/**
* Returns first loaded Class found in the searchPackages
* #param classname the simple class name (e.g. "String")
* #param searchPackages String[] of packages to search.
* <li>Place the more important packages at the top since the first Class
* found is returned</li>
* <code>//Example
* public static final String[] searchPackages = {
* "java.lang",
* "java.util",
* "my.company",
* "my.company.other" };
* </code>
* #return the loaded Class or null if not found
*/
public static final Class<?> findClassByName(String classname, String[] searchPackages) {
for(int i=0; i<searchPackages.length; i++){
try{
return Class.forName(searchPackages[i] + "." + classname);
} catch (ClassNotFoundException e){
//not in this package, try another
}
}
//nothing found: return null or throw ClassNotFoundException
return null;
}
same code modified to throw an exception if duplicate Class names found
/**
* Returns the loaded Class found in the searchPackages
* #param classname the simple class name (e.g. "String")
* #param searchPackages String[] of packages to search.
* <li>Place the more important packages at the top since the first Class
* found is returned</li>
* <code>//Example
* public static final String[] searchPackages = {
* "java.lang",
* "java.util",
* "my.company",
* "my.company.other" };
* </code>
* #throws RuntimeException if more than one class of the same classname found in multiple packages
* #return the loaded Class (guaranteed to be unique among the searchPackages) or null if not found
*/
public static final Class<?> findClassByNameNoDupes(String classname, String[] searchPackages) {
Class<?> foundClass = null;
for(int i=0; i<searchPackages.length; i++){
try{
boolean wasNull = foundClass == null;
foundClass = Class.forName(searchPackages[i] + "." + classname);
if (!wasNull) throw new RuntimeException(classname + " exists in multiple packages!");
} catch (ClassNotFoundException e){
//not in this package, try another
}
}
return foundClass;
}

That's not possible, classes are loaded dynamically once referenced. So, there is no way to drill down the list of available packages as there is no such thing.
However, there are ways to inspect jars as these are zip files (including the standard JVM jars).

Related

How to recommend parameters in java?

Is there any possible way to recommend parameters when I use the method? (Just like annotations?)
I made lots of static final String parameter for url connection and I want to know whether I use right input parameter or not when I code.
Below is my example.
public void myRequest(String inputParameter) {
String requestURL = "";
static final String ex1 = "http://example.com/xml1";
static final String ex2 = "http://example.com/xml2";
static final String ex3 = "http://example.com/xml3";
static final String ex4 = "http://example.com/xml4";
static final String ex5 = "http://example.com/xml5";
static final String ex6 = "http://example.com/xml6";
static final String ex7 = "http://example.com/xml7";
// too many..
// ....
static final String ex125 = "http://example.com/xm125";
if(inputParameter.equals("ex1")) {
requestURL = ex1;
} else if(inputParameter.equals("ex2")) {
requestURL = ex2;
}
// just like this..
// .....
else if(inputParameter.equals("ex125")) {
requestURL = ex125;
}
String requestURL = inputParameter;
URL url = new URL(requestURL);
URLConnection urlConnection = url.openConnection();
// below codes are unnecessary.
}
and I will use that method in the "main" method
public static void main(String[] args) {
myRequest("ex1"); // this!!
}
The point is, when I write the method "myRequest()", IDE will tell me the information about parameter (when the cursor is between '(' and ')'). The only one, that I can be noticed, is "You should write String object." not "You can use ex1 which means loading ex1.xml, ex2 meaning ex2.xml or ... ex125 meaning xm125.xml"
If my hope comes true, the result seems like this.
(Writing the methods)
myRequest(|); // there is cursor between ( and )
"What xml should I request? Umm.. there is ex1 to ex125. Ok.. ex1 means.. my hometown history.. ex2 means my school history.. and Umm.. I should use ex4 ok!"
(And I write below method)
myRequest("ex4");
I want IDE to inform me what String Parameter should I use.
Is there any possible way?
Given your updates to the question, the answer is build around enums and maps.
In other words: you simply, never ever put down a list of constants like you do there; that are then "mapped" (by hard wiring in your code; as you do in your example) to some other incoming strings.
Instead: you could use an enum to hold those constants; and you could also add some method to that enum class that knows how to map incoming strings to the available enum constants.
But the main point is: you want to abandon "raw" strings. The IDE (respectively the compiler) can't help you with adding an "ext1" string as method parameter.
But when you have:
public enum ExUrls {
EX1("http://example.com/xml1"), EX2("...
... a private constructor that takes that url string)
then you do:
void someMethod(ExURls ex) {
and all of a sudden, the IDE will be able to suggest the all potential ExUrl constants to you!
I'm not sure if I got your question right but you can use javadocs.
Here is an example from oracle.
/**
* Returns an Image object that can then be painted on the screen.
* The url argument must specify an absolute {#link URL}. The name
* argument is a specifier that is relative to the url argument.
* <p>
* This method always returns immediately, whether or not the
* image exists. When this applet attempts to draw the image on
* the screen, the data will be loaded. The graphics primitives
* that draw the image will incrementally paint on the screen.
*
* #param url an absolute URL giving the base location of the image
* #param name the location of the image, relative to the url argument
* #return the image at the specified URL
* #see Image
*/
public Image getImage(URL url, String name) {
try {
return getImage(new URL(url, name));
} catch (MalformedURLException e) {
return null;
}
}
All you need to do is type /** and press enter on top of your function then you can add details. These will show up when you hover to its function call.
In your case maybe like this
/**
* This method is very amazing it will cure cancer
* (ex1 - hometown history),
* (ex2 - school history),
* (ex3 - blah blah),
* (ex4 - what is the meaning of life),
* ...
* (ex125 - choose this)
*
* #param inputParameter - (String) You can input ex1 up to ex125
*/
public void myRequest(String inputParameter) {
but if you're looking to restrict input to ex1-ex125 only you need something else.

JasperReport: How to use subreport return values as input for Main Report Variable Calculation

Scenario:
I've two reports: Main Report (let's call it, A) and sub-report (let's call it, B).
Report A contains sub-report B at the detail band, so sub-report B is displayed for each element at the Report A datasource. Sub-report B also returns a variable to the Main report A.
What I want is to sum those return values from sub-report B and totalize them at the Main report summary.
To do that, I have tried to create a new report variable that sum those returns values... Something like this:
However, I've found that such variables expression are always evaluated before the band detail is rendered, so I always miss the first sub-report return value...
Sadly, the evaluation time (as this link says) cannot be changed on those kind of variables, so I'm stuck...
After been struggling with this for some hours... and searching the internet for a solution... I came with a Workaround (the enlightening forums were these ones: one and two).
First, you need to define a java Class Helper that allows you calculate some arithmetic operation, in my case a Sum operation. I defined these classes:
package reports.utils;
import java.util.Map;
/**
* Utility that allows you to sum Integer values.
*/
public class SumCalculator {
/**
* Stores a map of {#code SumCalculator} instances (A Map instance per thread).
*/
private static final ThreadLocalMap<String, SumCalculator> calculatorsIndex = new ThreadLocalMap<>();
/**
* The sum total.
*/
private int total = 0;
/**
* No arguments class constructor.
*/
private SumCalculator() {
super();
}
/**
* Instance a new {#code SumCalculator} with the given ID.
*
* #param id {#code SumCalculator}'s ID
* #return the new {#code SumCalculator} instance
*/
public static SumCalculator get(String id) {
Map<String, SumCalculator> map = calculatorsIndex.get();
SumCalculator calculator = map.get(id);
if (calculator == null) {
calculator = new SumCalculator();
map.put(id, calculator);
}
return calculator;
}
/**
* Destroy the {#code SumCalculator} associated to the given ID.
*
* #param id {#code SumCalculator}'s ID
* #return {#code null}
*/
public static String destroy(String id) {
Map<String, SumCalculator> map;
map = calculatorsIndex.get();
map.remove(id);
if (map.isEmpty()) {
calculatorsIndex.remove();
}
return null;
}
/**
* Resets the {#code SumCalculator} total.
*
* #return {#code null}
*/
public String reset() {
total = 0;
return null;
}
/**
* Adds the given integer value to the accumulated total.
*
* #param i an integer value (can be null)
* #return {#code null}
*/
public String add(Integer i) {
this.total += (i != null) ? i.intValue() : 0;
return null;
}
/**
* Return the accumulated total.
*
* #return an Integer value (won't be null, never!)
*/
public Integer getTotal() {
return this.total;
}
}
package reports.utils;
import java.util.HashMap;
import java.util.Map;
/**
* Thread Local variable that holds a {#code java.util.Map}.
*/
class ThreadLocalMap<K, V> extends ThreadLocal<Map<K, V>> {
/**
* Class Constructor.
*/
public ThreadLocalMap() {
super();
}
/* (non-Javadoc)
* #see java.lang.ThreadLocal#initialValue()
*/
#Override
protected Map<K, V> initialValue() {
return new HashMap<>();
}
}
Second, at your jasper report, you need to define four text fields:
1) A text field that iniatializes your calculator; it should be (ideally) at the title section of the report and should have an expression like this: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").reset(). This text field should have the evaluation time: NOW.
2) A text field that calls the increment function (i.e. SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").add($V{SUB_REPORT_RETURN_VALUE}). This text field will reside at your detail band, after the subreport element; and it should have the evaluation time: BAND (this is very important!!)
3) A text field that prints the calculator total. This text field will reside at your summary band, it will evaluate to NOW. Its expression will be: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").getTotal()
4) A text field that destroy the calculator. This text field will also reside at your summary band and must appear after the text field 3. The text field should have an expression like: SumCalculator.destroy("$V{SUB_REPORT_RETURN_VALUE}"). This text field should have the evaluation time: NOW.
Also, the text fields: 1, 2, and 4, should have the attribute "Blank when Null", so they will never be printed (that's why those java operations always return null).
And That's it. Then, your report can look something like this:
if i understand the problem, you can not summarize the amount returned by the sub report in the main report, i had the same problem and i solved in this way.
1.- Create a class which extends from net.sf.jasperreports.engine.JRDefaultScriptlet. and override the method beforeReportInit()
this is the code from this class.
package com.mem.utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
public class SumarizacionSubtotales extends JRDefaultScriptlet {
private final Log log = LogFactory.getLog(getClass());
private Double total;
public Double getTotal() {
return total;
}
public Double add(Double cantidad) {
if(log.isDebugEnabled())log.debug("AGREGANDO LA CANTIDAD : " + cantidad);
this.total += cantidad;
return cantidad;
}
#Override
public void beforeReportInit() throws JRScriptletException {
if(log.isDebugEnabled())log.debug("beforeReportInit");
total = 0.0D;
}
}
2.- add your project's jar in your ireport's classpath.
3.- Replace the class of the REPORT scriptlet.
in the properties with your class.
3.- add in the group footer where you want to print the value returned by the sub-report a textfield with the following expression.
$P{REPORT_SCRIPTLET}.add( $V{sum_detalles} )
In this case $V{sum_detalles} is a variable in the main report which contains the value returned by the sub-report.
4.- Add in the Last page footer another textfield with the following expression.
$P{REPORT_SCRIPTLET}.getTotal()

Cannot find symbol - method print()

I cannot see why this code is giving me the error cannot find method print everything looks okay to me, and I've been over the code checking for spelling errors and tried a different version of it that basically did the same thing but instead of things being called account they were called student. Ignore the comments as I have not changed them
import java.util.*;
public class AccountList
{
private ArrayList < Account > accounts;
/**
* Create a LabClass with no limit on number of enrolments.
* All other details are set to default values.
*/
public AccountList()
{
accounts = new ArrayList < Account >();
}
/**
* Add a account to this LabClass.
*/
public void addAccount(Account newAccount)
{
accounts.add(newAccount);
}
/**
* Return the number of accounts currently enrolled in this LabClass.
*/
public int getNumberOfAccounts()
{
return accounts.size();
}
/**
* Print out a class list with other LabClass
* details to the standard terminal.
*
* Method uses a for .. each loop
*/
public void getAllAccounts()
{
for(Account account : accounts)
{
**account.print();**
}
System.out.println("Number of accounts: " + getNumberOfAccounts());
}
/**
* Print out details of a account
* #param accountEntry The entry in the list
*/
public void getAccount(int accountEntry)
{
if(accountEntry < 0)
{
System.out.println("Negative entry :" + accountEntry);
}
else if(accountEntry < getNumberOfAccounts())
{
Account account = accounts.get(accountEntry);
System.out.print(account);
}
else
{
System.out.println("No such entry :" + accountEntry);
}
}
/**
* removes a account from the list
* #param accountEntry The entry in the list
*/
public void removeAccount(int accountEntry)
{
if(accountEntry < 0)
{
System.out.println("Negative entry :" + accountEntry);
}
else if(accountEntry < getNumberOfAccounts())
{
accounts.remove(accountEntry);
}
else
{
System.out.println("No such entry :" + accountEntry);
}
}
/**
* removes a account from the list
*
* #param aAccount the account to remove
*/
public void removeAccount(Account aAccount)
{
accounts.remove(aAccount);
}
}
You seem to be missing some fundamental concepts here.
First: you have no "default" .print() method; that is, the base, bare-bones Java class Object has no .print() method.
Second: even if it had, what do you expect it to do anyway? Where do you want it to print, what do you want it to print? The first question (where) is answered by classes dedicated to performing output duties (a PrintStream for instance), the second question (what) is answered by implementing your class' .toString().
Since you Account class is obviously not a class dedicated to output duties, you need to do two things:
make your Account class override .toString();
use a dedicated output class to print it; the fastest way to do this is to use System.out, which happens to be a PrintStream, which implements a .print() method.
Seeing your code it appears that you have a .printAccountDetails() method; this contradicts the Law of Demeter for starters; and note how it uses System.out.
Also, the difference between .print() and .println() in a PrintStream (which System.out is) is that a newline will be appended to the output if you use the "ln version"; custom has it that for most text based output channels, this also triggers an output flush from the underlying OS libraries.

right way to use collections in Java?

I have the following code. However I am doubting about if it is the right way to implement it or not.
What I mean is: in the collection framework there are many data structures to use and creating the class (MemberList) to manage the aggregations of many members can be implemented using ArrayList, LinkedList, priority queue ...
I would like to use a data structure that fits with my needs, and that has the least Big O possible when it comes to searching, sorting, deleting, adding, modifying and deleting.
public class MemberList{
/**
*a list of accounts existing in the database
*/
private static List<Member> members = new ArrayList<Member>();
/**
* add a member to our member list
* #param m the member to be added
*/
public static void Add(Member m)
{
members.add(m);
/**
* delete a member from our member list
* #param m the member to be deleted
*/
public static void Delete(Member m)
{
Iterator<Member> it = members.iterator();
while(it.hasNext())
{
if(m.equals(it.next()))
{
it.remove();
}
}
}
/**
* Search for a specific member in the member list
* #param m the member that needs to be found
* #return the reference of the object Member
* #throws UserNotFoundExeption whether the member was not found in the list
*/
public static Member Search (Member m) throws UserNotFoundExeption
{
Iterator<Member> it = members.iterator();
while(it.hasNext())
{
if(m.equals(it.next()))
{
return it.next();
}else{
UserNotFoundExeption ex = new UserNotFoundExeption(it.next().getUsername());
throw ex;
}
}
return null;
}
/**
* The login method enables checking whether the login was made successfully or not. if not, it can throw two
* exceptions to handle the errors
* #param member
* #return
* #throws UserNotFoundExeption
* #throws FailedLoginException
*/
public static boolean login (Member m)
throws UserNotFoundExeption,FailedLoginException {
try{
Member member = Search(m);
if (!m.authenticate(member.getPassword()))
{
FailedLoginException ex2 = new FailedLoginException (member.getPassword());
throw ex2;
}
else
{
return true;
}
}catch(UserNotFoundExeption ex){
throw ex;
}
}
/**
* this behavior modify attributes of the corresponding class
* #param <T> this generic helps to accept any type of parameter change, hence we can change any type
* #param m this is the member that need to change his information
* #param choice the choice of which information to change
* #param change the new change on the member attribute
* #throws UserNotFoundExeption
*/
public static <T> void Modify(Member m, int choice, T change) throws UserNotFoundExeption
{
try{
Member member = Search(m);
switch(choice)
{
case 1:
member.setUsername((String)change);
break;
case 2:
member.setPassword((String)change);
break;
case 3:
member.setCommunity((Community)change);
break;
}
}catch(UserNotFoundExeption ex){
throw ex;
}
}
/**
* display the member list objects information
*/
public static void Display()
{
Iterator<Member> it = members.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
/**
* Sort objects in the list
*/
public static void Sort()
{
Iterator<Member> it = members.iterator();
Member[] Members_Array = members.toArray(new Member[members.size()]);
Member temp;
for(int i = 0; i<members.size(); i++)
{
for(int j = 0; j < members.size() - (i+1); j++)
{
if(Members_Array[j].compareTo(Members_Array[j+1]) > 0)
{
temp = Members_Array[j];
Members_Array[j] = Members_Array[j+1];
Members_Array[j+1] = temp;
}
}
}
}
}
Thank you!
This question is too broad, and "the right way to use collections in Java" is also a philosophical question, so it cannot be scientifically answered.
Specifically to your case, depending on the pool of your members, you probably don't want to iterate over them when you need to pull a member out. I would recommend you use something like a HashMap<String,Member>, where each member has an identifiable unique key (a username for instance). This will grant you O(1) access speed and allow you to iterate when you need it using .values().
You can use a HashMap like so:
// This is how you create a hash map:
HashMap<String,Member> members = new HashMap<String,Member>();
// This is how you add an object to it. It is slower than lists,
// but since reading happens far often, it pays off.
members.put("ben", new Member());
// This is how you access an object in the hash map.
// Accessing a hash map is O(1).
Member member = members.get("ben");
// This is how you remove an object from the hash map.
// Removing an object is also O(1)
members.remove("ben");
// Hash maps are also iterable
for(Member member : members.values()) {
}
I would use array list if you dont want to use JDBC.
But later if your project going to growe, you have to use JDBC.

read a file using Scanner: Why am I getting an error when using Scanner for read files in java?

This example demonstrates using Scanner to read a file line by line (it does not perform a write operation) I don't know why I get an error when I try to compile. Could somebody explain the reason to me?. I'm using jcreatorLE and JDK 1.6 to run my program:
import java.io.*;
import java.util.Scanner;
public final class File_read {
public static void main(String... aArgs) throws FileNotFoundException {
ReadWithScanner parser = new ReadWithScanner("C:\\Temp\\test.txt");
parser.processLineByLine();
log("Done.");
}
/**
* #param aFileName full name of an existing, readable file.
*/
public ReadWithScanner(String aFileName){
fFile = new File(aFileName);
}
/** Template method that calls {#link #processLine(String)}. */
public final void processLineByLine() throws FileNotFoundException {
Scanner scanner = new Scanner(fFile);
try {
//first use a Scanner to get each line
while ( scanner.hasNextLine() ){
processLine( scanner.nextLine() );
}
}
finally {
//ensure the underlying stream is always closed
scanner.close();
}
}
/**
* Overridable method for processing lines in different ways.
*
* <P>This simple default implementation expects simple name-value pairs, separated by an
* '=' sign. Examples of valid input :
* <tt>height = 167cm</tt>
* <tt>mass = 65kg</tt>
* <tt>disposition = "grumpy"</tt>
* <tt>this is the name = this is the value</tt>
*/
protected void processLine(String aLine){
//use a second Scanner to parse the content of each line
Scanner scanner = new Scanner(aLine);
scanner.useDelimiter("=");
if ( scanner.hasNext() ){
String name = scanner.next();
String value = scanner.next();
log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()) );
}
else {
log("Empty or invalid line. Unable to process.");
}
//(no need for finally here, since String is source)
scanner.close();
}
// PRIVATE //
private final File fFile;
private static void log(Object aObject){
System.out.println(String.valueOf(aObject));
}
private String quote(String aText){
String QUOTE = "'";
return QUOTE + aText + QUOTE;
}
}
This is the result from running it:
--------------------Configuration: <Default>--------------------
C:\Users\administrador\Documents\File_read.java:15: invalid method declaration; return type required
public ReadWithScanner(String aFileName){
^
1 error
Process completed.
When you lifted that code from here :-), you renamed the class but not the constructor. Only constructors are allowed to not have return types.
I suggest you either rename the class back or rename the constructor.
I hope this isn't homework. As it stands, your educator would have an easy time proving plagiarism. You'll need to at least change the variable names as well as class names, you might want to also reformat it a bit including changing the order of methods in the class.
That's if it's homework. Which it's not, right? :-)
Your "ReadWithScanner" constructor needs to match the name of the class ("File_read")
public File_read(String aFileName){
fFile = new File(aFileName);
}
Your class is named File_read and your constructor is named ReadWithScanner. The warning is that your constructor needs to be named the same as the class.
The name of the class is File_read, so the constructor name should be File_read but you gave the name as ReadWithScanner that is why its complaining. Compiler thinking its a method name so expecting a return type.

Categories