Table with more then one level of metatables wont convert into JSON

I have 2 Modules
GenericItem and GenericWeapon

GenericItem creates a table with

function module.New(Data)
	local self = Data
	self.Name = Data.Name or Data.GenericName or ""
	self.GenericName = Data.GenericName or "Unknown"
	self.CoreType = "Item"
	self.ID = Data.ID or HttpService:GenerateGUID(false)
	setmetatable(self,{__index = module})
	return self
end

where module has a few methods (using JSONEncode on this stores it fine)
then the GenericWeapon creates a new GenericItem and adds 2 metatables

function module.New(Data)
	local self = {}
	local sub = GenericItem.New(Data)
	setmetatable(sub,{__index = module})
	setmetatable(self,{__index = sub})
	return self
end

running JSONEncode on a GenericWeapon.New() returns “[]” whereas if I run JSONEncode on a GenericItem.New() it returns the data
Also, the module in GenericWeapon inherits the methods from GenericItem

Is it possible to store the GenericWeapon as a JSON?

Following how it’s described here (All about Object Oriented Programming), and from experience, this should work:

function module.New(Data)
    local self = GenericItem.New(Data)
    setmetatable(self,{__index = module})
    return self
end

“GenericItem.New(Data)” already returns a metatable with all of GenericItem’s methods. “setmetatable(self,{__index = module})” will then write the methods from GenericWeapon to “self” which gets returned. I tested it, and it seems to work.

Disclaimer:
My explanation may not be the best. But you should get the idea, if not look at the thread I linked.

1 Like

JSONEncode only encodes what’s in the given table, not what’s in the metatable. The metatable is entirely ignored.

In GenericItem, the properties (Name, GenericName, etc.) are in the table.

In GenericWeapon, you use the GenericItem.new() with its properties as GenericWeapon’s metatable, so the properties are in the metatable, not in the table.

This means that GenericItem.new() returns a table with properties in it (and a metatable), and GenericWeapon.new() returns an empty table (and a metatable).


You shouldn’t be storing any modifiable data in the metatable. You should use it for methods or constant static properties.

One way to fix this is to make the following change to GenericWeapon:

setmetatable(module, {__index = GenericItem}) 

function module.New(Data)
	local self = GenericItem.New(Data)
	setmetatable(self,{__index = module})
	return self
end

An unrelated tip: you can avoid {__index = module} by making __index part of module:

module.__index = module

function module.New(Data)
	local self = Data
	self.Name = Data.Name or Data.GenericName or ""
	self.GenericName = Data.GenericName or "Unknown"
	self.CoreType = "Item"
	self.ID = Data.ID or HttpService:GenerateGUID(false)
	setmetatable(self, module)
	return self
end
module.__index = module

setmetatable(module, GenericItem) 

function module.New(Data)
	local self = GenericItem.New(Data)
	setmetatable(self, module)
	return self
end
3 Likes