Java | Хранение экземпляра класса

144
05 января 2021, 06:10

Делаю бота для Telegram на Java. При разработке столкнулся с тем, что система хранит где-то объект и отправляет его параметры несмотря на то, что объект пересоздан.

Как это должно работать
1. Пользователь что-то пишет боту
2. Бот получает из класса Main - HashMap с объектами User, где ключ - уникальный идентификатор пользователя внутри Telegram.
3. Если данных в HashMap по пользователю нет - бот создаёт экземпляр класса User()
3.1 Конструктор в User делает запрос к базе данных и сохраняет в переменных все значения (nickname, id, TelegramID и так далее).
4. Вызывается метод isRegister() класса User, который проверяет заполнился ли объект конструктором и если нет, то пользователь не зарегистрирован. Если да - сохраняет экземпляр класса в HashMap
5. Отправляется в ответ сообщение о том что пользователь: зарегистрирован / не зарегистрирован

Как это работает сейчас
1. Пользователь что-то пишет боту
2. Бот проверяет есть ли данные в HashMap (их нет, потому что программа пока не сохраняет их там)
3. Бот создаёт экземпляр класса User и заполняет его данными из базы конструктором
4. Если экземпляр пуст, то пишет что пользователь не зарегистрирован. Если заполнен - пишет что зарегистрирован
5. Если пользователь не зарегистрирован, при попытке что-то написать, каждый раз выводится сообщение что юзер не зарегистрирован.
6. Создаём в базе данных запись с данными пользователя
7. Пишем боту и он отвечает что пользователь зарегистрирован
8. Меняем идентификатор пользователя в базе на любой другой
9. Бот до сих пор пишет что пользователь зарегистрирован и выводит данные ранее заполненного объекта User. Даже если боту написать с другого аккаунта - всё равно выводит данные первого аккаунта

Не совсем понятно где сохраняется объект User и почему сохраняется, когда каждый раз должен создаваться заново и заново наполняться или быть пустым (если данных нет).

Код

Core

package org.teateam.Chat;
import org.teateam.Main;
import org.teateam.TelegramApi;
import org.teateam.User;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
public class Core extends Thread{
    @Override
    public void run(){
        System.out.println("Chat flow started");
        // Telegram startup section
        Main.telegramApi = new TelegramApi();
        TelegramBotsApi botsApi = new TelegramBotsApi();
        try {
            botsApi.registerBot(Main.telegramApi);
        }
        catch (TelegramApiException ex){
            ex.printStackTrace();
        }
        // End section
    }
    public static void validateText(String text, long from_id) {
        User user = Main.users.get(from_id);
        if(user == null){
            // If not online
            user = new User(from_id);
            if(user.isRegister()) {
                Main.telegramApi.sendTextMessage(from_id, "Вы зарегистрированы. Nickname: " + user.nickname + ". Tid: " + user.tid);
            }
            else{
                Main.telegramApi.sendTextMessage(from_id, "Вы не зарегистрированы");
            }
        }
        else{
            Main.telegramApi.sendTextMessage(from_id, "Your nick is " + user.nickname);
        }
    }
}


Обрабатывает новые события в методе validateText(), пришедшие от метода onUpdateReceived() в классе TelegramApi

TelegramApi

package org.teateam;
import org.teateam.Chat.Core;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
public class TelegramApi extends TelegramLongPollingBot {
    private SendMessage message = new SendMessage();
    public TelegramApi(){
        System.out.println("Bot has been started success");
    }
    public void sendTextMessage(long peer_id, String text){
        this.message.setChatId(peer_id).setText(text);
        try {
            execute(this.message);
        }
        catch (TelegramApiException tEx){
            System.out.println("Exception in org.teateam.TelegramApi: " + tEx);
        }
    }
    @Override
    public void onUpdateReceived(Update update) {
        if(update.hasMessage() && update.getMessage().hasText()){
            // If text
            Core.validateText(update.getMessage().getText(), update.getMessage().getChatId());
            System.out.println(" ");
            System.out.println("New message: " + update.getMessage().getText());
            System.out.println("From ID: " + update.getMessage().getChatId());
            System.gc();
        }
    }
    @Override
    public String getBotUsername() {
        return Main.getBotUsername();
    }
    @Override
    public String getBotToken() {
        return Main.getAccess_token();
    }
}

validateText() проверяет есть ли объект User в HashMap (его всегда нет в данной реализации) и создаёт объект класса User.

User

package org.teateam;
import java.util.ArrayList;
public class User {
    public long tid;
    public String nickname;
    public int accessLevel;
    public int id;
    public boolean online;
    public int room;
    public User(long tid){
        // Add data from database
        String query = "SELECT * FROM `users` WHERE `tid` = '" + tid + "' LIMIT 1;";
        ArrayList<String> result = MySQL.select(query);
        if(!result.isEmpty()) {
            this.tid = Long.parseLong(result.get(0));
            this.nickname = result.get(1);
            this.accessLevel = Integer.parseInt(result.get(2));
            this.id = Integer.parseInt(result.get(3));
            this.online = false;
            this.room = 0;
        }
    }
    public boolean isRegister(){
        return this.nickname != null;
    }
}


User, при создании, делает запрос к базе через метод select() класса MySQL и получает от него ArrayList, которым заполняет самого себя. Если MySQL возвращает пустой ArrayList, то экземпляр класса не заполняется.

MySQL

package org.teateam;
import java.sql.*;
import java.util.ArrayList;
public class MySQL {
    private static final String host = "";
    private static final int port = 3306;
    private static final String user = "";
    private static final String password = "";
    private static final String database = "";
    private static final String url = "jdbc:mysql://" + host + ":" + port + "/" + database + "?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
    private static Connection connection;
    private static Statement statement;
    private static ResultSet resultSet;
    private static ResultSetMetaData resultSetMetaData;
    private static ArrayList<String> result = new ArrayList<>();
    /**
     *
     * @param query For example: SELECT `login` FROM `users` WHERE `id` = 1 LIMIT 1;
     * @return ArrayList<String>
     */
    public static ArrayList<String> select(String query){
        try{
            connection = DriverManager.getConnection(url, user, password);
            statement = connection.createStatement();
            resultSet = statement.executeQuery(query);
            resultSetMetaData = resultSet.getMetaData();
            try {
                while (resultSet.next()) {
                    for(int i = 0; i < resultSetMetaData.getColumnCount(); i++){
                        result.add(resultSet.getString(i + 1 ));
                        System.out.println(resultSet.getString(i + 1));
                    }
                }
            }
            catch (SQLException sqlEx){
                sqlEx.printStackTrace();
                return result;
            }
        }
        catch (SQLException sqlEx){
            sqlEx.printStackTrace();
        }
        finally {
            try{ connection.close(); } catch (SQLException se) { /* TODO anything */ se.printStackTrace();}
            try{ statement.close(); } catch (SQLException se) { /* TODO anything */ se.printStackTrace();}
            try{ resultSet.close(); } catch (SQLException se) { /*  TODO anything */ se.printStackTrace();}
        }
        return result;
    }
}


Answer 1

В классе MySQL есть private static ArrayList result, который хранит значения. В случае, если данные есть в базе - он наполняется и потом возвращается в User. В случае, если данных нет в базе, но до этого этот объект User уже вызывался- с result ничего не происходит и он возвращается с последним значением. Собственно, result и хранил в себе все данные, по которым заполнялся User и не переопределялся в конце.

Решено добавлением следующей строки в начале метода select() класса MySQL:

result.clear();

Что позволяет каждый раз очищать ArrayList от последнего запроса.

READ ALSO
Почему возникает ошибка OutOfMemoryError?

Почему возникает ошибка OutOfMemoryError?

Вводится из консоли дата (тип String)При посимвольном сравнении, на второй вводимой дате вылетает ошибка java

113
Алгоритм вычленения &gt;3 &lt;6 значного числа

Алгоритм вычленения >3 <6 значного числа

Требуется алгоритм который бы вытащил >3 <6 значное число из строки

92
Как один класс может реализовать 2 интерфейса?

Как один класс может реализовать 2 интерфейса?

Читаю книгу по паттернам (паттерны проектирования, Эрик и Элизабет Фримен42 ст

105
Конфигурация spring-webmvc.xml

Конфигурация spring-webmvc.xml

Помогите сконфигурировать Spring

98