#Storing Custom Variable POJOs in Firebase
1 messages · Page 1 of 1 (latest)
Stacktrace when I try to save the POJO with a custom type:
org.bukkit.event.EventException: null
at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:310) ~[spigot-api-1.19-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-api-1.19-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:588) ~[spigot-api-1.19-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:575) ~[spigot-api-1.19-R0.1-SNAPSHOT.jar:?]
at net.minecraft.server.players.PlayerList.remove(PlayerList.java:501) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1725) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.network.NetworkManager.m(NetworkManager.java:416) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.network.ServerConnection.c(ServerConnection.java:193) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1312) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.dedicated.DedicatedServer.b(DedicatedServer.java:394) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.MinecraftServer.a(MinecraftServer.java:1197) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.MinecraftServer.v(MinecraftServer.java:1010) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:291) ~[spigot-1.19-R0.1-SNAPSHOT.jar:3540-Spigot-56be6a8-0231a37]
at java.lang.Thread.run(Thread.java:833) [?:?]
Caused by: com.google.firebase.database.DatabaseException: No properties to serialize found on class net.minecraft.resources.ResourceKey
at com.google.firebase.database.utilities.encoding.CustomClassMapper$BeanMapper.<init>(CustomClassMapper.java:538) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.loadOrCreateBeanMapperForClass(CustomClassMapper.java:316) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.serialize(CustomClassMapper.java:171) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.access$300(CustomClassMapper.java:51) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper$BeanMapper.serialize(CustomClassMapper.java:797) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.serialize(CustomClassMapper.java:172) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.access$300(CustomClassMapper.java:51) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper$BeanMapper.serialize(CustomClassMapper.java:797) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.serialize(CustomClassMapper.java:172) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.access$300(CustomClassMapper.java:51) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper$BeanMapper.serialize(CustomClassMapper.java:797) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper$BeanMapper.serialize(CustomClassMapper.java:797) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.serialize(CustomClassMapper.java:172) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.access$300(CustomClassMapper.java:51) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper$BeanMapper.serialize(CustomClassMapper.java:797) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.serialize(CustomClassMapper.java:172) ~[?:?]
at com.google.firebase.database.utilities.encoding.CustomClassMapper.convertToPlainJavaTypes(CustomClassMapper.java:65) ~[?:?]
at com.google.firebase.database.DatabaseReference.setValueInternal(DatabaseReference.java:297) ~[?:?]
at com.google.firebase.database.DatabaseReference.setValueAsync(DatabaseReference.java:178) ~[?:?]
at dev.danmizu.skylands.player.PlayerMap.savePlayerData(PlayerMap.java:147) ~[?:?]
at dev.danmizu.skylands.player.PlayerMap.endPlayerData(PlayerMap.java:151) ~[?:?]
at dev.danmizu.skylands.player.PlayerMap.unloadPlayer(PlayerMap.java:82) ~[?:?]
at dev.danmizu.skylands.events.PlayerLeave.onLeave(PlayerLeave.java:20) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:306) ~[spigot-api-1.19-R0.1-SNAPSHOT.jar:?]
... 13 more
POJO Class:
package dev.danmizu.skylands.player;
// java imports
import java.util.HashMap;
import java.util.Map;
// gson imports
import com.google.gson.Gson;
import com.google.cloud.firestore.annotation.Exclude;
import com.google.cloud.firestore.annotation.PropertyName;
import com.google.common.reflect.TypeToken;
// bukkit imports
import org.bukkit.Location;
public class PlayerData {
//player's display name
private String displayName;
//player's current health
private double health;
//player's location
private Location location;
// CONSTRUCTORS
public PlayerData() {}
public PlayerData(String displayName) {
this.displayName = displayName;
}
public PlayerData(String displayName, double health) {
this.displayName = displayName;
this.health = health;
}
public PlayerData(String inputDisplayName, double inputHealth, Location inputLocation) {
this.displayName = inputDisplayName;
this.health = inputHealth;
this.location = inputLocation;
}
// GETTERS/SETTERS
@PropertyName("displayName")
public String getDisplayName() {
return displayName;
}
@PropertyName("health")
public double getHealth() {
return health;
}
@PropertyName("health")
public void setHealth(double input) {
health = input;
}
@PropertyName("location")
public Location getLocation() {
return this.location;
}
@PropertyName("location")
public void setLocation(Location input) {
this.location = input;
}
// UTILITY
@Exclude
public String toJSON() {
//convert player entry to json
return new Gson().toJson(this);
}
@Exclude
public Map<String, Object> toMap() {
//convert player entry to json then to map
return new Gson().fromJson(toJSON(), new TypeToken<HashMap<String, Object>>() {}.getType());
}
}
it cannot serialize the location because its trying to serialize the world
record SerializableLocation
(double x, double y, double z, double yaw, double pitch, UUID world) {
public Location toLocation() {
return new Location(Bukkit.getWorld(world), x, y, z, yaw, pitch);
}
public static SerializableLocation fromLocation(Location loc) {
return new SerializableLocation(loc.getX(), loc.getY(), loc.getZ(),
loc.getYaw(), loc.getPitch(),
loc.getWorld().getUID());
}
}
``` use something like that
instead of org.bukkit.Location
put this in the PlayerData class
or even better, use the UUID
@hard vortex
@fathom bane trying to implement the record in the playerdata class
no it has to be lowercase record
it is 17 pretty sure
for what versiion are you developing
it says
1.7
in the error message
so dont think so
check it in either gradle or maven settings, or check it in Project Structure if youre not using a build system
Location isnt accepting yaw and pitch
record SerializableLocation
(double x, double y, double z, float yaw, float pitch, UUID world) {
new declaration line
awesome
once its all working how would I use it where I store and retrieve from firebase?
do i change my location type to that
yeah
when storing the data you would first convert the Location to a SerializableLocation using SerializableLocation.fromLocation(loc)
and then loading the data you can convert the serializable location to a Location using serializableLocation.toLocation()
and then cache that and use it
I changed my POJO to use SerializableLocation instead of Location as that variables type. I store the location to the instance within the PlayerMove event for now to test so I changed it to this:
PlayerMap.getPlayerData(player).setLocation(SerializableLocation.fromLocation(player.getLocation()));
setLocation is from the PlayerData class
now it uses SerializableLocation type
SerializableLocation is a seperate class I made to define the type
which has the function that "casts" it
going to test it now
seems fine
hm
Caused by: com.google.firebase.database.DatabaseException: No properties to serialize found on class dev.danmizu.skylands.type.SerializableLocation
same issue I think
package dev.danmizu.skylands.type;
// java imports
import java.util.UUID;
// bukkit imports
import org.bukkit.Bukkit;
import org.bukkit.Location;
public record SerializableLocation(double x, double y, double z, float yaw, float pitch, UUID world) {
public Location toLocation() {
return new Location(Bukkit.getWorld(world), x, y, z, yaw, pitch);
}
public static SerializableLocation fromLocation(Location loc) {
return new SerializableLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), loc.getWorld().getUID());
}
}
SerializableLocation class
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
Stacktrace
could it just have to do with firebase having specific accepted types?
let me look it up
p
oh
at the bottom it says POJOs are accepted but maybe the accepted types still apply
they have to be public
right click in the SerializableLocation class, and go to Generate and then Getters
and then choose the format get<Name>
idk what its called
also it may be a problem with it being a record
as its final
does it need to have getters and setters in the type? I thought it meant for the actual POJO
cuz I have a getter and setter in the pojo
so change it to
class SerializableLocation {
public double x, y, z;
public float yaw, pitch;
public UUID world;
// the functions
}
``` and then right click -> `Generate` -> `Getters and Setters`
package dev.danmizu.skylands.type;
// java imports
import java.util.UUID;
// bukkit imports
import org.bukkit.Bukkit;
import org.bukkit.Location;
class SerializableLocation {
public double getX() {
return this.x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return this.y;
}
public void setY(double y) {
this.y = y;
}
public double getZ() {
return this.z;
}
public void setZ(double z) {
this.z = z;
}
public float getYaw() {
return this.yaw;
}
public void setYaw(float yaw) {
this.yaw = yaw;
}
public float getPitch() {
return this.pitch;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
public UUID getWorld() {
return this.world;
}
public void setWorld(UUID world) {
this.world = world;
}
public double x, y, z;
public float yaw, pitch;
public UUID world;
public SerializableLocation(double x2, double y2, double z2, float yaw2, float pitch2, UUID uid) {
}
public Location toLocation() {
return new Location(Bukkit.getWorld(world), x, y, z, yaw, pitch);
}
public static SerializableLocation fromLocation(Location loc) {
return new SerializableLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), loc.getWorld().getUID());
}
}
this look right?
yeah
it asked me to have a constructor too
the class should be public right
cuz i get errors saying the class isnt accessible otherwise
oh yeah
@hard vortex put two constructors;
public SerializableLocation(double x, double y, double z,
float yaw, float pitch, UUID world) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.world = world;
}
public SerializableLocation() {
}
second one is needed for firebase to work i think
yeah
okay so it somewhat works!
on the first time I join and leave its able to store it
second time I get an error but I think it has to do with retrieving the data on join
so for some reason its not able to take the data and create a new POJO with it
yea the error is on every move event
I have to use SerializableLocation again to parse it back when I retrieve the data right
or do I have to change the PlayerData pojo so it can do that?
public static void retrievePlayerData(Player player, @Nonnull final onPlayerDataRetrievalCallback callback) {
//set player data reference
DatabaseReference refPlayers = Firebase.getInstance().getReference("players").child(player.getUniqueId().toString());
//DEBUG
TextUtil.sendConsoleLog("Player Data Retrieving");
//retrieve player data from database
refPlayers.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
//DEBUG
TextUtil.sendConsoleLog("Player Data Retrieved");
callback.onPlayerDataRetrieval(snapshot.getValue(PlayerData.class));
}
@Override
public void onCancelled(DatabaseError error) {
}
});
}
you can see at callback.onPlayerDataRetrieval(snapshot.getValue(PlayerData.class));
no idea how firebase works
when it gets the data (snapshot) its using the POJO
so idk what im looking at
most of it is not important just that line really
ah
thats all because it needs to get the data asynchronously so that means 50x more code to get it to work in java
yeah lmao
so is there something I have to do with the getter/setter in PlayerData to make it parse the data back from the database as the SerializableLocation type?
it would be much cleaner if they did it like
ref
.whenSuccess(value -> ...)
.whenError(error -> ...)
.releaseWhenDone();
idk what the issue is man
maybe ask in #help-development again
about thsi new issue