Getting the guild owner in JDA raising NullPointerException - java

I was trying to make a function which displays info about the server.
public static void serverInfo(Guild guild, MessageChannel channel) {
EmbedBuilder embed = new EmbedBuilder();
//Calculations
int people = 0;
int roles = 0;
int tc = 0;
int vc = 0;
for (Member member : guild.getMembers()) {
if (!member.getUser().isBot())
++people;
}
for (Role ignored : guild.getRoles())
++roles;
for (TextChannel ignored : guild.getTextChannels())
++tc;
for (VoiceChannel ignored : guild.getVoiceChannels())
++vc;
String time = String.valueOf(guild.getTimeCreated());
String created = time.substring(8, 10) + "-" + time.substring(5, 7) + "-" + time.substring(0, 4);
embed.setTitle(guild.getName());
embed.setThumbnail(guild.getIconUrl());
embed.addField("Total Members", String.valueOf(guild.getMemberCount()+1), true);
embed.addField("Members", String.valueOf(people),true);
embed.addField("Bots", String.valueOf((guild.getMemberCount()+1)-people), true);
embed.addField("Owner", Objects.requireNonNull(guild.getOwner()).getUser().getName(), true);
embed.addField("Roles", String.valueOf(roles), true);
embed.addField("Text Channels", String.valueOf(tc), false);
embed.addField("Voice Channels", String.valueOf(vc), true);
embed.addField("Date Created", created, false);
channel.sendMessageEmbeds(embed.build()).queue();
}
However, this raises a NullPointerException
java.lang.NullPointerException at
java.base/java.util.Objects.requireNonNull(Objects.java:208) at
com.television.Commands.Infos.serverInfo(Infos.java:38) at
com.television.CommandExecutor.onMessageReceived(CommandExecutor.java:19)
But, if I removed this part from the function, it works just fine, and no exception is raised.
for (Member member : guild.getMembers()) {
if (!member.getUser().isBot())
++people;
}
Why does this happen? This problem also gets raised only in 1 server, out of the 3 servers I've tested in.
And, secondly, I know this is not much related to the question from the title, how can I calculate the number of members/bots because this part (the for-each loop in the code snippet above) does not calculate the number of members correctly, it always has 1 as the value of the bot variable, and therefore number of members - 1 is the value of people.

Two things in advance: You have to either cache all the members from every guild or instead (recommended) retrieve them when needed. To be able to do so, you need to enable the GUILD_MEMBERS Privileged Intent.
You can pretty easily retrieve a List representing all members of a guild with the following method:
public CompletableFuture<List<Member>> loadMembersFull(Guild guild) {
CompletableFuture<List<Member>> future = new CompletableFuture<>();
if (guild.isLoaded()) {
future.complete(guild.getMembers());
} else {
guild.loadMembers()
.onError(future::completeExceptionally)
.onSuccess(future::complete);
}
}
With that you can then move on with all your other stuff.
I actually don't know why it would work without the for-loop, but it looks like the error does not occur there, but when loading the owner, as it throws the exception in your #requireNonNull.
The owner object is null when he/she is no longer in the guild or not yet loaded. The owner could also have deleted the account or get banned by Discord.
To also solve this problem, I recommend you to replace your line with the following one:
embed.addField("Owner", Optional.ofNullable(guild.getOwner()).map(owner -> owner.getUser().getName()).orElse("<not found>"), true);
To get the proper amount of users, you should filter the list of users for whether they are bots or not.
int amount = (int) loadMembersFull(guild).join().stream()
.map(Member::getUser)
.filter(user -> !user.isBot())
.count();
If you need more help, feel free to ask me on my Discord server

Related

Java/Android studio : For loop - Same data shows multiple times

So I am trying to create this page that compares a user's interest with other users and shows the list of all those users.. Now, with the for loop i created, one particular user's name repeats until the end of the loop. I only one one name per username to appear on the textfield.. However, I don't know how to do that.. Here's my code for showing users with common interests:
Realm realm= Realm.getDefaultInstance();
RealmResults<interests> result=realm.where(interests.class).findAll();
RealmResults<Users> user=realm.where(Users.class).findAll();
for(int i=0;i<result.size();i++)
{
for(int j=0;j<result.size();j++)
{
if(result.get(i).getId().equals(userid))
{
if(result.get(i).getInterest().equals(result.get(j).getInterest()))
{
if(!result.get(j).getId().equals(userid)) {
users = result.get(j).getId();
interestss.append("Interests :" + result.get(i).getInterest());
}
}
id.append("\n"+users);
}
}
}
for(int i=0;i<result.size();i++)
{
for(int j=0;j<result.size();j++)
{
if(result.get(i).getId().equals(userid))
{
if(result.get(i).getInterest().equals(result.get(j).getInterest()))
I'm almost 98% sure that you shouldn't even need to write this kind of code if you use Realm's query system and a link query, instead of looping and comparing things manually.
RealmResults<Interests> interests = realm.where(Interests.class)
.equalTo("user.userId", userId)
.findAll();
Which should be possible if you have a backlink from Interests to Users.
// in Interests class
#LinkingObjects("interest")
private final RealmResults<User> user = null;

Invoke Methods Dynamically on Java

At work, we have to generate a report for our client that changes its parameters several times during the week.
This report is generated from a single table on our database.
For example, imagine a table that has 100 columns and I have to generate a report with only 5 columns today, but tomorrow I have to generate with 95 of them.
With this in mind, I created a TO class with all the columns of the specified table and my query returns all columns (SELECT * FROM TABLE).
What I'm trying to create is a dynamic form to generate the report.
I first thought on create a simple frame with a list of the columns listed as check boxes and the user would select the columns that he wants (of course with a button to Select All and another to Deselect All).
As all of the columns have the same name as the attributes of the TO class, I developed the following code (I have Google this):
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
Is this the better way to do what I need to?
Thanks in advance.
Obs.: the getters of the TO class have the pattern "getAttribute_Name".
Note: This question is different from the one where the user is asking HOW to invoke some method given a certain name. I know how to do that. What I'm asking is if this is the better way to solve the problem I described.
My Java is a little more limited, but I believe that's about as good as you're going to get using reflection.
Class<?> c = Test.class;
for (String attribute : listOfAttributes) {
auxText += String.valueOf(c.getMethod("get" + attribute).invoke(this, null));
}
But since this sounds like it's from potentially untrusted data, I would advise using a HashMap in this case, with each method explicitly referenced. First of all, it explicitly states what methods can be dynamically called. Second, it's more type safe, and compile-time errors are way better than runtime errors. Third, it is likely faster, since it avoids reflection altogether. Something to the effect of this:
private static final HashMap<String, Supplier<Object>> methods = new HashMap<>();
// Initialize all the methods.
static {
methods.set("Foo", Test::getFoo);
methods.set("Bar", Test::getBar);
// etc.
}
private String invokeGetter(String name) {
if (methods.containsKey(name)) {
return String.valueOf(methods.get(name).get());
} else {
throw new NoSuchMethodException();
}
}
It might sound like a major DRY violation to do so, but the repetition at least makes sure you don't wind up with unrelated getters accidentally called.
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
You can do this somewhat more elegantly via Java Beans, the Introspector, and PropertyDescriptor, but it's a little more long-winded:
Map<String, Method> methods = new HashMap<>();
Class c = this.getClass(); // surely?
for (PropertyDescriptor pd : Introspector.getBeanInfo(c).getPropertyDescriptors())
{
map.put(pd.getName(), pd.getReadMethod();
}
//
for (int i = 0; i < listOfAttributes.length; i++)
{
Method m = methods.get(listOfAttributes[i]);
if (m == null)
continue;
auxText += String.valueOf(m.invoke(this, null));
}

How to say String A > String B in Java

I'm working on a small program to compare service levels, the user will input the service level 2 times (current and requested) and then the input will be scanned and compared and show a message.
For example:
current = 9*5 NBD (a)
requested = 24*7 SBD (b)
I want to know how in Java I can tell the compiler that (b) is greater than (a)
Because I want to use if statement like this
if (b > a) then show message.
I tried to use string.equals, but didn't help me too much.
I was not successful to convert string to number to do such comparison.
Try following statement
if(a.compareTo(b) > 0);
First thing: you can't override String.compareTo(), because it's final. you can create class with String field and write compareTo() for this class. This is not best idea.
But you can compare two strings by putting them into array and creating implementation of Comparator interface in sort() method.
String current = "9*5 NBD";
String requested = "24*7 SBD";
String[] test = {current, requested};
Arrays.sort(test, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
//Your impl goes here
return 0;
}
});
Where do these strings come from? Surely they must be from some kind of table that contains the service level details together with the cost of subscribing to that service level. What you want to check is whether the required service level costs more than the service level the client already has. Suppose the service level details come from a Map<ServiceLevel, BigDecimal> that gives the cost for a certain service level. Then all you need to do is:
BigDecimal costOfCurrentSL = serviceLevelCosts.get(currentSL);
BigDecimal costOfRequiredSL = serviceLevelCosts.get(requiredSL);
if (costOfRequiredSL.compareTo(costOfCurrentSL) > 0) {
// ... tell client he needs to purchase a top-up
}
Thank you all for the willing to help :)
After a lot of thinking I found another way which helped me a lot
I created 2 new integers and called them Values of what I need.
and used if statement, that if the entered is 9*5 NBD so the value will be zero, and if it is SBD, the value will be 1 and so on, then created new if statement to compare the values and show me a message if the A is greater than B, and it really worked.
Here is a part of my code
String WA_SLA = "", REQ_SLA = "";
int Va_WA_SLA = 0, Va_REQ_SLA = 0;
if(WA_SLA.equalsIgnoreCase("9*5 SBD"))
{
Va_WA_SLA = 1;
}
if(REQ_SLA.equalsIgnoreCase("9*5 NBD"))
{
Va_REQ_SLA = 0;
}
if(Va_WA_SLA > Va_REQ_SLA)
{
JOptionPane.showMessageDialog(frame,"Warranty SLA is Higher than Requested SLA " ,null, JOptionPane.INFORMATION_MESSAGE);
}
Thaaaaaaaaaaaaank you a lot

SmartFoxServer 2x using sfsApi, NullPointerException

I am simply trying to set a room variable (adding the user's name to a room varible) in my UserJoinedRoomHandler:
From my JAVA extension:
public class UserJoinedRoomHandler extends BaseServerEventHandler
{
#Override
public void handleServerEvent(ISFSEvent arg0) throws SFSException
{
User user = (User) arg0.getParameter(SFSEventParam.USER);
Room room = (Room) arg0.getParameter(SFSEventParam.ROOM);
trace("add p1 = " + user.getName() + " to room=" + room.getId());
List<RoomVariable> listOfVars = new ArrayList<RoomVariable>();
listOfVars.add( new SFSRoomVariable("player1Name", user.getName()) );
((MyExtension) getParentExtension()).sfsApi.setRoomVariables(user, room, listOfVars); // NullPointerException here :(
}
}
Note, I grab the sfsAPI when in MyExtention init() function:
ISFSApi sfsApi = SmartFoxServer.getInstance().getAPIManager().getSFSApi();
To me this should work, the only thing I can think of is that the room might not have fully initialised (the user had just created the room before this event is fired). But in any case I thought this should be a trivial scenario, but it has cost me a good handful of hours already.
Cheers for any help.
The solution was to use the Api directly:
((MyExtension) getParentExtension()).getApi().setRoomVariables(user, room, listOfVars);
PS: Unfortunately there is no method to issue 1 Room Variable. You have to submit a list, even if its only 1 in length.

There are errors but I can't see where

For some reason I am receiving errors in the code below and I can't see why, can you spot any?
public void delTask_mouseClicked(MouseEvent e)
{
if(delTask.isEnabled() == false) {
int numTasks = taskTable.getRowCount();
Object[] currentTasks;
currentTasks = new Object[numTasks];
for (int i = 0; i < numTasks ; i++){
Object tasks = taskTable.getModel().getValueAt(i, 1);
currentTasks[i] = tasks;
}
System.out.println(currentTasks);
}
}
Thanks for the help, it's really appreciated.
There massive block of errors I am getting is below:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at projecttaskmanagement.ProjectGUI.delTask_mouseClicked(ProjectGUI.java:233)
at projecttaskmanagement.ProjectGUI$2.mouseClicked(ProjectGUI.java:109)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:212)
at java.awt.Component.processMouseEvent(Component.java:5520)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3135)
at java.awt.Component.processEvent(Component.java:5282)
at java.awt.Container.processEvent(Container.java:1966)
at java.awt.Component.dispatchEventImpl(Component.java:3984)
at java.awt.Container.dispatchEventImpl(Container.java:2024)
at java.awt.Component.dispatchEvent(Component.java:3819)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3901)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
at java.awt.Container.dispatchEventImpl(Container.java:2010)
at java.awt.Window.dispatchEventImpl(Window.java:1791)
at java.awt.Component.dispatchEvent(Component.java:3819)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
CODE AT LINE 233:
int numTasks = taskTable.getRowCount();
TASK TABLE IS DEFINED BELOW:
String[] taskcolumnNames = {"ID #",
"Name",
"Description",
"Start Date",
"End Date",
"Staff",
"Completed"};
Object[][] taskdata = {
{new Integer(1), "Requirements Analysis",
"Analysing the requirements",
"01/09/2011", "15/10/2011",
"Bob", new Boolean(true)},
{new Integer(2), "System Design",
"Designing the System",
"15/09/2011", "15/10/2011",
"Alice", new Boolean(true)},
{new Integer(3), "Code (A)",
"Part 'A' of coding",
"01/10/2011", "15/11/2011",
"David", new Boolean(true)},
};
JTable taskTable = new JTable(taskdata, taskcolumnNames);
While we're waiting for you to post the actual errors you're getting (a), please take a moment to NEVER do this:
if (delTask.isEnabled() == false)
A much better form is the simpler-to-read:
if (! delTask.isEnabled())
We now return you to your scheduled programming, pending your update.
Dum de dum de dum ...
Now, based on your update, the following part of the stackdump:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at projecttaskmanagement.ProjectGUI.delTask_mouseClicked(ProjectGUI.java:233)
indicates where the problem lies. Find out which of those lines of yours in line number 233 and there you have it. The thing that you're trying to deference on that line is in fact a null reference.
Based on the snippet, it'll probably be one of the following lines:
public void delTask_mouseClicked(MouseEvent e)
{
if(delTask.isEnabled() == false) { // <--
int numTasks = taskTable.getRowCount(); // <--
Object[] currentTasks;
currentTasks = new Object[numTasks];
for (int i = 0; i < numTasks ; i++){
Object tasks = taskTable.getModel().getValueAt(i, 1); // <--
currentTasks[i] = tasks;
}
System.out.println(currentTasks);
}
}
The first will be because delTask itself is null, the second if taskTable is null.
The third will be if taskTable itself is valid but the value returned from its getModel() method is null.
So, it appears that your taskTable is null. As to why this is so, that's unknowable based on the current information. What you will need to do is examine all the places it's set to a valid value and ensure that this happens before you (or more likely, AWT under the control of your user) call this method.
And of course, make sure it's not set back to NULL at some point after creation.
If you can't guarantee that, you'll probably need to change:
if (delTask.isEnabled() == false)
into something like:
if ((! delTask.isEnabled()) && (taskTable != NULL))
but my preference would be to fix the root cause of the problem rather than applying this band-aid.
Your code that creates the JTable seems okay (syntactically) but there's the slight mystery of where that's done. Is it created in a manner that it's usable from where you're trying to use it.
For example, if that code that creates it is within the constructor, that particular taskTable would be local to said constructor (and destroyed on exit), not usable from elsewhere. In that case, it needs to be made an object-level variable so that other methods can get to it.
You can see that effect in the following program:
public class testprog {
public Object thingOne;
public Object thingTwo;
public void someFunction() {
thingOne = new Object();
Object thingTwo = new Object();
}
public void debug() {
if (thingOne == null)
System.out.println ("thingOne is NULL");
else
System.out.println ("thingOne is valid");
if (thingTwo == null)
System.out.println ("thingTwo is NULL");
else
System.out.println ("thingTwo is valid");
}
public static void main(String args[]) {
testprog tp = new testprog();
tp.someFunction();
tp.debug();
}
}
This outputs:
thingOne is valid
thingTwo is NULL
because thje thingTwo set up in someFunction() is a local version and does not in any way set up the object-level thingTwo - the object level one remains as null and, if you try to dereference it, you'll see the same problem you're having.
(a) The best problems reports come with a small, complete code snippet exhibiting the problem, the expected behaviour, and the actual behaviour.
If we post that sample of yours into a naked Eclipse Java program, it's very much not complete. MouseEvent, delTask and taskTable have no definitions and, without that information, it's a little hard to debug.
In addition, Eclipse (for syntax errors) and Java itself (for runtime errors) are perfectly able to tell you in great detail what your problems are, and you should read what it's telling you. You should also communicate that information to us if you want help :-)
Which line is line 233 of ProjectGUI.java? At least one of the following is null:
delTask
taskTable
taskTable.getModel()
Figure out which of those falls on line 233 (per your error report), and you've figured out where the problem lies. We'll need to see more code to determine why the variable does not have the expected value.

Categories

Resources