Abstract Generic Object class - java

Hi
In the game Minecraft you have to send data between the client and the server in order to sync stuff, one of the things that need to be synced in particular circumstances is TileEntities with a render. The data is stored on the server and sent to the client which is thereafter used for render.
You create a class that contains the data that needs to be synced and attach it to a channel creation API called "SimpleImpl". My Network object and a Message Object:
public class IntercraftPacketHandler
{
private static int index = 1;
private static final ResourceLocation CHANNEL_NAME = new ResourceLocation(Reference.MODID,"network");
private static final String PROTOCOL_VERSION = new ResourceLocation(Reference.MODID,"1").toString();
public static SimpleChannel getNetworkChannel()
{
final SimpleChannel channel = NetworkRegistry.ChannelBuilder.named(CHANNEL_NAME)
.clientAcceptedVersions(version -> true)
.serverAcceptedVersions(version -> true)
.networkProtocolVersion(() -> PROTOCOL_VERSION)
.simpleChannel();
// Sync Capability Identity Hidden data message.
channel.messageBuilder(MessageIdentityHidden.class,index)
.encoder(MessageIdentityHidden::encode)
.decoder(MessageIdentityHidden::decode)
.consumer(MessageIdentityHidden::handle)
.add(); index++;
// Send TreeTapTileEntity data to client.
channel.messageBuilder(MessageTreeTap.class,index)
.encoder(MessageTreeTap::encode)
.decoder(MessageTreeTap::decode)
.consumer(MessageTreeTap::handle)
.add(); index++;
// Send ChunkLoaderTileEntity data to client.
channel.messageBuilder(MessageChunkLoader.class,index)
.encoder(MessageChunkLoader::encode)
.decoder(MessageChunkLoader::decode)
.consumer(MessageChunkLoader::handle)
.add(); index++;
return channel;
}
}
public class MessageChunkLoader
{
private BlockPos pos;
private boolean canLoad;
public MessageChunkLoader(BlockPos pos,boolean canLoad)
{
this.pos = pos;
this.canLoad = canLoad;
}
public void handle(Supplier<NetworkEvent.Context> ctx)
{
ctx.get().enqueueWork(() -> {
try {
ChunkLoaderBaseTileEntity tile = (ChunkLoaderBaseTileEntity) Minecraft.getInstance().world.getTileEntity(pos);
tile.canLoad = canLoad;
} catch (NullPointerException err) {
System.out.println(String.format("Could not find ChunkLoaderTileEntity at %s %s %s!",pos.getX(),pos.getY(),pos.getZ()));
}
});
}
public static void encode(MessageChunkLoader message, PacketBuffer buffer)
{
buffer.writeBlockPos(message.pos);
buffer.writeBoolean(message.canLoad);
}
public static MessageChunkLoader decode(final PacketBuffer buffer)
{
return new MessageChunkLoader(buffer.readBlockPos(),buffer.readBoolean());
}
}
I then initialize it in my main mod class used by objects in my mod project.
#Mod(Reference.MODID)
public class IntercraftCore
{
public static final SimpleChannel NETWORK = IntercraftPacketHandler.getNetworkChannel();
...
The problem and this post's question; right now I create a new message class from the formula I follow in MessageChunkLoader (public static encode & decode method and a handle method). I would like to create a more generic class for creating message classes for TileEntities, but I'm having problems with that. Here's the current class:
public abstract class MessageTileEntity<T extends TileEntity>
{
protected final BlockPos pos;
protected final Class<T> clazz;
public MessageTileEntity(BlockPos pos, Class<T> clazz)
{
this.pos = pos;
this.clazz = clazz;
}
public abstract void handle(Supplier<NetworkEvent.Context> ctx);
protected T getTileEntity()
{
try {
return clazz.cast(Minecraft.getInstance().world.getTileEntity(pos));
} catch (NullPointerException e) {
System.out.println(String.format("Could not find %s at [%d %d %d]!",clazz.getSimpleName(),pos.getX(),pos.getY(),pos.getZ()));
throw e;
} catch (ClassCastException e) {
System.out.println(String.format("TileEntity at [%d %d %d] is not %s!",pos.getX(),pos.getY(),pos.getZ(),clazz.getSimpleName()));
throw e;
}
}
public static void encode(MessageTileEntity message, PacketBuffer buffer)
{
}
public static MessageTileEntity decode(final PacketBuffer buffer)
{
return null;
}
}
The main problem is I lack the proper Java skills to make it like I want it to function. The method handle is easy as it's non-static and needs to be custom to every TileEntity message, but the methods encode and decode which needs to be static gives me problems. I have no idea what I'm trying to achieve is possible, asking won't hurt. Maybe the solution is easier than I think.

Related

Play 1.3 Event Stream implementation

So I've been trying to implement a proper EventStream solution using Play Framework 1.3, however I just can't get it to work properly. An exception keeps getting thrown but I'm not sure what the cause is.
Can anyone provide an example implementation or point me in the direction of one?
This is the method I have in my controller.
public static void stream() {
response.contentType = "text/event-stream";
response.encoding = "UTF-8";
response.status = 200;
response.chunked = true;
// a record of the last ID that this request... requested
Long lastId = 0L;
// since this request has only been initiated, the first thing to do is return a list of whats in the queue
List<F.IndexedEvent> archive = StreamQueue.getRecentNotifications(lastId);
if (!archive.isEmpty()) {
// write that list out in the response
response.writeChunk(//a string representing the entire list as a single event);
// update out internal reference to the lastId
lastId = archive.get(archive.size() - 1).id;
}
// keep this connection alive
while (true) {
// await the promise of more notifications for the stream
List<F.IndexedEvent<StreamQueue.Notification>> notifications = await(StreamQueue.getNextNotification(lastId));
// for each notification, write it out as a separate event
for (int i = 0; i < notifications.size(); i++) {
response.writeChunk(//a string representing a single event using notifications.get(i));
// update out internal reference to the lastId
lastId = notifications.get(i).id;
}
}
}
And this is my implementation of the queue StreamQueue.java:
public class StreamQueue {
final ArchivedEventStream<StreamQueue.Notification> notifications = new ArchivedEventStream<StreamQueue.Notification>(100);
static StreamQueue instance = null;
public static StreamQueue get() {
if(instance == null) {
instance = new StreamQueue();
}
return instance;
}
// the method to call when I want to send an event
public static void alert(Notification.Type type, Object... args){
get().addMessage((String) args[0]);
}
public static F.Promise<java.util.List<F.IndexedEvent<Notification>>> getNextNotification(Long lastId) {
return get().getNotificationsStream().nextEvents(lastId);
}
public static java.util.List<F.IndexedEvent> getRecentNotifications(Long lastId) {
return get().getNotificationsStream().availableEvents(lastId);
}
public ArchivedEventStream<StreamQueue.Notification> getNotificationsStream() {
return notifications;
}
private void addMessage(String message){
notifications.publish(new StreamQueue.MessageEvent(message));
}
public static abstract class Notification extends F.IndexedEvent {
public enum Type {
ISSUE,
MESSAGE;
}
final public Type type;
final public Long timestamp;
public Notification(Type type) {
super(type);
this.type = type;
this.timestamp = System.currentTimeMillis();
}
public Long getId() {
return this.id;
}
public String toJson() {
return new JSONSerializer().exclude("class").serialize(this);
}
}
public static class MessageEvent extends StreamQueue.Notification {
public final String message;
public MessageEvent(String message) {
super(Type.MESSAGE);
this.message = message;
}
public String toJson() {
return new JSONSerializer().include("message").exclude("*").serialize(this);
}
}
}
And finally, here's the exception I'm getting:
Internal Server Error (500) for request GET /stream
Execution exception
InvocationTargetException occured : null
play.exceptions.JavaExecutionException
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:230)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.reflect.InvocationTargetException
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:524)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:475)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:451)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:446)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:160)
... 1 more
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to java.util.Map
at controllers.StreamController.stream(StreamController.java)
... 6 more
The exception seems to be thrown as a result of ArchivedEventStream.nextEvents(...) which I'm calling from StreamQueue.getNextNotification(...). The cause appears to be a Long being cast to a Map but at no point do I attempt to do that.
Thanks in advance for your help!
UPDATE
So I tried my project in Play 1.2.5 and the streaming works perfectly. However, the project demands we use Play 1.3.
The cause is at bottom of the stacktrace:
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to java.util.Map
I think you are trying to cast Notification.timestamp to map in StreamController.

Unexpected slowness in Play framework project with Mongodb and Morphia

I am building a RSS reader using the Play Framework, play authenticate, and mongodb accessed through Morphia. It's running on a Ubuntu server with a VIA Nano processor U2250 (1.6GHz Capable) and 2ghz ram apparently. Despite every tweak and optimization I could think of, I still observe insane delays in the answering time: from 2seconds to 1 minute to answer a simple HTTP GET request to mark an item as read (I'll talk about this example because it is simple). Note that i am not facing this problem on local tests on my personal machine, just on remote deployment.
Profiling gives me the following distribution of spent time to answer a dozen "mark as read" requests :
org.bson.io.PoolOutputBuffer.pipe() 11%
org.bson.io.Bits.readFully() 10%
scala.concurrent.forkjoin.ForkJoinPool.scan() 8%
org.jboss.netty.channel.socket.nio.SelectorUtil.select() 7%
org.bson.io.PoolOutputBuffer.write 5%
com.google.code.morphia.mapping.DefaultCreator.getNoArgsConstructor() 5%
from which I gathered the I/O with the database was the bottleneck. I have made the references explicit using a custom class Ref<> because Key<> was handling package names fairly poorly. Therefore the aforementioned mark as read request only does 3 db queries : retrieve the item by its ref (id), retrieve the inbox by its ref (id) stored in the session cache, remove the item from the inbox and store it back again. My interactions with the database are encapsulated in a static helper class :
public class MorphiaHelper {
static private Mongo mongo;
static private Morphia morphia;
static private Datastore datastore;
public static void mapModels() {
morphia.map(...);
}
public static void startup() {
try {
mongo = new MongoClient();
morphia = new Morphia();
datastore = MorphiaHelper.morphia.createDatastore(MorphiaHelper.mongo, "dbname");
mapModels();
updateModelsIfNeeded();
datastore.ensureIndexes();
datastore.ensureCaps();
} catch (Exception e) {
Logger.error("Database failed to initialize:" + e.getMessage());
}
Logger.debug("** mongo and morphia initialization on datastore: " + MorphiaHelper.datastore.getDB());
}
public static void shutdown() {
mongo.close();
Logger.debug("** mongo and morphia closed **");
}
public static <T> Key<T> save(T entity){
return datastore.save(entity);
}
public static <T, V> T get(Ref<V> ref) throws NotFoundException{
try {
Class<T> classT = (Class<T>)Class.forName(ref.getClassName());
return datastore.get(classT, ref.getId());
} catch (ClassNotFoundException e) {
throw new NotFoundException("Reference to morphia not found:" + ref.toString());
}
}
...
}
and rely on the aforementionned inner static Ref class :
public static interface Referencable{
Ref getRef();
}
public static class Ref<T> implements Serializable, Comparable {
Map<String, String> id;
private static String nameToKey(String name){
return name.replace(".", " ");
}
private static String keyToName(String key){
return key.replace(" ", ".");
}
public static <T> Ref<T> fromIdString(Class<T> className, String idString) {
return new Ref<T>(className, idString);
}
public static Ref<?> fromString(String sourceRefString) throws ClassNotFoundException {
if (! sourceRefString.contains("=")){
throw new ClassNotFoundException();
}
String[] parseString = sourceRefString.split("=", 2);
Class<?> className = Class.forName(keyToName(parseString[0]));
return fromIdString(className, parseString[1]);
}
#Deprecated
private Ref() {}
public Ref(Class<T> _className, String _id) {
id = Collections.singletonMap(nameToKey(_className.getName()), _id);
}
private Entry<String, String> getIdFromMap(){
return id.entrySet().iterator().next();
}
public Object getId(){
return getIdFromMap().getValue();
}
public String toString(){
return getIdFromMap().toString();
}
#Override
public boolean equals(Object other){
return (other.getClass().equals(this.getClass())
&& ((Ref)other).getIdFromMap().getKey().equals(this.getIdFromMap().getKey())
&& ((Ref)other).getIdFromMap().getValue().equals(this.getIdFromMap().getValue()));
}
#Override
public int hashCode() {
return getIdFromMap().hashCode();
}
public String getClassName() {
return keyToName(getIdFromMap().getKey());
}
#Override
public int compareTo(Object arg0) {
return this.toString().compareTo(((Ref) arg0).toString());
}
}
Since I haven't been able to clearly locate the problem, I am also offering you just in case the code of the controller :
public static Result read(final String id) throws NotFoundException{
Item item = MorphiaHelper.get(Ref.fromIdString(Item.class, id));
Application.getLocalInbox().remove(item);
return ok();
}
This is Application, getting us the inbox :
public class Application extends Controller {
public static Inbox getLocalInbox() throws NotFoundException {
return Inbox.getInboxOfUser(getLocalUserRef());
}
public static User getLocalUser() throws NotFoundException {
User user = UserDAO.findUser(PlayAuthenticate.getUser(session()));
session("UserRef", user.getRef().toString());
return user;
}
public static Ref<User> getLocalUserRef() throws NotFoundException {
if (session("UserRef") == null){
session("UserRef", getLocalUser().getRef().toString());
}
try {
return (Ref<User>) Ref.fromString(session("UserRef"));
} catch (Exception e){
throw new NotFoundException("could not retrieve current user ref");
}
}
}
So yeah nothing very interesting here. This is inbox.remove :
public void remove(Item item) {
// TODO can be optimized if we dont check the existence of tags
boolean listContainedElement = false;
for(Ref<Tag> tag : item.getTagsRef()){
List<Ref<Item>> list = inbox().get(tag);
if (list != null){
Ref<Item> key = item.getRef();
boolean remove = list.remove(key);
listContainedElement = listContainedElement || remove;
if (list.size() == 0){
inbox().remove(tag);
}
}
}
List<Ref<Item>> list = inbox.get(Tag.getUntagged());
if (list != null){
listContainedElement = listContainedElement || list.remove(item.getRef());
}
if (listContainedElement) seen(item);
MorphiaHelper.save(this);
}
where
Map<String, List<Ref<Item>>> inbox = new HashMap<String, List<Ref<Item>>>();
Map<Ref<Tag>, List<Ref<Item>>> inbox(){
return new MorphiaMap(inbox);
}
is a way to bypass the fact that morphia cannot handle anything else than Strings as map keys and keep code clean, MorphiaMap being a class storing an attribute "Map innerMap;" and forwarding all the commands with the String to Ref translation.
I'm completely at a loss here so any kind of advice would be much appreciated. I've been tweaking the system for weeks to improve performances but I'm afraid I'm missing the elephant in the room.
Thank you in advance
Best regards

Java Object Serialization nested objects

I was studying Serialization in Java when I came across saving the state of objects which are not serializable and are referenced in Class(instance variables) to be serialized. In the following code, I am having class Dog (Serializable) which has reference to class Collar(not serializable); which in turn has reference to class Color (not serializable). I am getting error despite trying all the possibilities. This is the latest code I came up with:
class Color {
private String colorName;
public String getColorName() {
return colorName;
}
public void setColorName(String colorName) {
this.colorName = colorName;
}
Color(String color) {
this.colorName = color;
}
}
class Collar {
private Color color;
private int size;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
Collar(int size, Color color) {
this.size = size;
this.color = color;
}
}
class Dog implements Serializable {
Dog(String breed, Collar collar) {
this.breed = breed;
this.collar = collar;
}
private String breed;
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public Collar getCollar() {
return collar;
}
public void setCollar(Collar collar) {
this.collar = collar;
}
transient private Collar collar;
private void writeObject(ObjectOutputStream os) {
try {
os.defaultWriteObject();
os.writeInt(this.getCollar().getSize());
os.writeUTF(this.getCollar().getColor().getColorName());
os.close();
} catch (IOException ex) {
Logger.getLogger(Dog.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void readObject(ObjectInputStream is) {
try {
is.defaultReadObject();
int size = is.readInt();
String colorName = is.readUTF();
this.setCollar(new Collar(size, new Color(colorName)));
is.close();
} catch (Exception ex) {
Logger.getLogger(Dog.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class App0001 {
public static void main(String[] args) {
try {
Dog d = new Dog("Great Dane", new Collar(3, new Color("RED")));
//System.out.println(d.getCollar().getColor().getColorName());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("obj.ser"));
os.writeObject(d);
os.close();
ObjectInputStream is = new ObjectInputStream(new FileInputStream("obj.ser"));
d = (Dog) is.readObject();
System.out.println(d.getCollar().getColor().getColorName());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
And I am getting following error:
java.io.IOException: Write error
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:260)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1847)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1756)
at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1257)
at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1211)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1395)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:333)
at Serialization.App0001.main(App0001.java:121)
This is not a production code. This is just for practice and understanding.
You must not close the streams in readObject and writeObject! If you do so, the next write/read attempt fails.
Usually, streams (as other resources) should be treated as follows:
If your method owns the stream, i.e. your method opened it - close it
in the same method (usually this is done in a try-with-resource
statement).
If your method does NOT own the stream, i.e. it got the stream passed from somewhere else (usually passed via method parameter), don't close it as you don't know what the owner of the stream wants to do with it after your method returns.
When writing to a stream, the "Write error" in an IOException occurs, if the stream is closed.
Analyzing your code, I see that you have a custom writeObject method in your class Dog. In that you must not close the stream, as it is needed for continued writing. So just remove the line
os.close();
in your writeObject method. Oh, and also remove the line
is.close();
in the readObject method.
Ok, I will explain it a bit more. You have the following code in your main method:
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("obj.ser"));
os.writeObject(d);
os.close();
Here you are creating the stream, using it, and afterwards you close it. This is the correct place to close it, as this is the responsible place for the stream.
Imagine, you have a nested structure of serializable objects, whose class definitions all contain a custom writeObject method. When calling the writeObject method of an ObjectOutputStream, it walks through the object graph with calling the writeObject method of each object. The ObjectOutputStream is controlling the write order, and it also write control bytes itself. Creating and closing must be done outside (as you already did).

Best practice to prevent further instantiation of java classes

I have some class storing keys with important information. No one else is allowed to create a key, since a key relys on static information (like certain directory structures etc.).
public final class KeyConstants
{
private KeyConstants()
{
// could throw an exception to prevent instantiation
}
public static final Key<MyClass> MY_CLASS_DATA = new Key<MyClass>("someId", MyClass.class);
public static class Key<T>
{
public final String ID;
public final Class<T> CLAZZ;
private Key(String id, Class<T> clazz)
{
this.ID = id;
this.CLAZZ = clazz;
}
}
}
This example is simplyfied.
I wanted to test the consequences of a wrong key (exception handling, etc.) and instantiated the class via reflection in a JUnit test case.
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(String.class, Class.class);
c.setAccessible(true);
#SuppressWarnings ("unchecked")
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c.newInstance("wrongId", MyClass.class);
Then I asked myself how could I prevent further instantiation of the key class (i. e. preventing further object creating via reflection)?
enums came to my mind, but they don't work with generics.
public enum Key<T>
{
//... Syntax error, enum declaration cannot have type parameters
}
So how can I keep a set of n instances of a generic class and prevent further instantiation?
So how can I keep a set of n instances of a generic class and prevent
further instantiation?
If you truly want to use this pattern, then no one (including you) should be able to instantiate a Key object. In order to keep a set of n instances in a class with this pattern, you could have a private constructor, a static method for access and a SecurityManager to prevent reflection. And since you want to be able to access the keys as pubic constants, I would try something like this..
public class KeyConstants{
// Here are your n instances for public access
public static final int KEY_1 = 1;
public static final int KEY_2 = 2;
.
.
.
public static final int KEY_N = 'n';
// now you can call this method like this..
// Key mKey = KeyConstants.getKey(KeyConstants.KEY_1);
public static Key getKey(int key){
List keys = Key.getInstances();
switch(key){
case KEY_1:
return keys.get(0);
case KEY_2:
return keys.get(1);
.
.
.
case KEY_N:
return keys.get(n);
default:
// not index out of bounds.. this means
// they didn't use a constant
throw new IllegalArgumentException();
}
}
static class Key<T>{
private static List<Key> instances;
private String ID;
private Class<T> CLAZZ;
private Key(String id, Class<T> clazz){
this.ID = id;
this.CLAZZ = clazz;
}
public static List<Key> getInstances(){
if(instances == null){
instances = new ArrayList<Key>();
//populate instances list
}
return instances;
}
}
}
Use SecurityManager to prevent reflection access.
//attempt to set your own security manager to prevent reflection
try {
System.setSecurityManager(new MySecurityManager());
} catch (SecurityException se) {
}
class MySecurityManager extends SecurityManager {
public void checkPermission(Permission perm) {
if (perm.getName().equals("suppressAccessChecks"))
throw new SecurityException("Invalid Access");
}
}
This will throw a SecurityException anytime someone attempts to access a private variable or field in your class (including access attempts via reflection).
I'm not sure I fully understand your question, but if a private constructor is not sufficient, can you use a more dynamic approach and throw an exception in the constructor after a signal is given? For example:
public static class Key<T>
{
private static boolean isLocked = false;
// Call this method when you want no more keys to be created
public static void lock() { isLocked = true; }
...
private Key(String id, Class<T> clazz)
{
if (isLocked) throw new IllegalStateException("Cannot create instances of Key");
this.ID = id;
this.CLAZZ = clazz;
}
}
Then - and this is the disadvantage - you will have to call Key.lock() once you want to prevent more instances being created.
As you showed in your code to prevent instantiating KeyConstants you can throw some Exception inside private-non-argument constructor.
Harder part is way to block creating KeyConstants.Key constructor from outside of KeyConstants class.
Some wild idea
Maybe create Exception in your constructor and check how its stack trace looks like. When I add this code to constructor
private Key(String id, Class<T> clazz) {
StackTraceElement[] stack = new Exception().getStackTrace();
for (int i=0; i<stack.length; i++){
System.out.println(i+") "+stack[i]);
}
this.ID = id;
this.CLAZZ = clazz;
}
and create instance of Key with reflection like
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(
String.class, Class.class);
c.setAccessible(true);
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c
.newInstance("wrongId", MyClass.class);
I get
0) KeyConstants$Key.<init>(Test.java:38)
1) sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
2) sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
3) sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
4) java.lang.reflect.Constructor.newInstance(Constructor.java:525)
so maybe just if 4th element of stack is java.lang.reflect.Constructor.newInstance throw Exception to prevent executing rest of constructors code like:
if (stack.length>=4 && stack[4].toString().startsWith("java.lang.reflect.Constructor.newInstance")){
throw new RuntimeException("cant create object with reflection");
}
I came across some Multiton patterns recently, where I tried to handle problems with unique enum keys, that gave me the idea of another approach.
The keys can be used for information flow as I intended, or even as keys for typesafe heterogeneous container, where they can perform compile-time casting.
Key-defining class
public class KeyConstants
{
public static final KeysForIntegers SOME_INT_KEY = KeysForIntegers.KEY_2;
public static final KeysForStrings SOME_STRING_KEY = KeysForStrings.KEY_1;
public interface Key<Type>
{
public Class<Type> getType();
}
/* Define methods that classes working with the keys expect from them */
public interface KeyInformation
{
public String getInfo1();
// and so on...
}
public enum KeysForStrings implements Key<String>, KeyInformation
{
KEY_1("someId");
public final String ID;
private KeysForStrings(String id)
{
ID = id;
}
#Override
public String getInfo1()
{
return "Good piece of information on " + ID + ".";
}
#Override
public Class<String> getType()
{
return String.class;
}
}
public enum KeysForIntegers implements Key<Integer>, KeyInformation
{
KEY_2("bla");
public final String ID;
private KeysForIntegers(String id)
{
this.ID = id;
}
#Override
public String getInfo1()
{
return "Some info on " + ID + ".";
}
#Override
public Class<Integer> getType()
{
return Integer.class;
}
}
}
Example key-using class
public class KeyUser
{
public static void main(String[] args)
{
KeysForIntegers k1 = KeyConstants.SOME_INT_KEY;
KeysForStrings k2 = KeyConstants.SOME_STRING_KEY;
processStringKey(k2);
useIntKey(k1);
Integer i = useIntKey(KeyConstants.SOME_INT_KEY);
processStringKey(KeyConstants.SOME_STRING_KEY);
}
/* My methods should just work with my keys */
#SuppressWarnings ("unchecked")
public static <TYPE, KEY extends Enum<KeysForIntegers> & Key<TYPE> & KeyInformation> TYPE useIntKey(KEY k)
{
System.out.println(k.getInfo1());
return (TYPE) new Object();
}
public static <KEY extends Enum<KeysForStrings> & KeyInformation> void processStringKey(KEY k)
{
System.out.println(k.getInfo1());
// process stuff
}
}
I have another approach, you can bound an interface in a way to only be implemented by enum.
With that approach you have a fixed set of instances at compile time.
If you want to add lazy loading, the enums implementing it should be proxies that load the desired object if it is requested. The class or classes that are hidden behind the proxies should only be visible to them, so that they have exclusive access to the constructor.
public class User {
public static <S> S handleKey(FixedInstanceSet<S,?> key) {
return key.getKey();
}
}
interface FixedInstanceSet<S, T extends Enum<T> & FixedInstanceSet<S,T>>
{
public S getKey();
}
enum StringKeys implements FixedInstanceSet<String, StringKeys> {
TOP, DOWN, LEFT, RIGHT;
#Override
public String getKey() { return null; }
}
enum IntKeys implements FixedInstanceSet<Integer, IntKeys > {
TOP, DOWN, LEFT, RIGHT;
#Override
public Integer getKey() { return null; }
}
/*
* Bound mismatch: The type NotWorking is not a valid substitute for the bounded
* parameter <T extends Enum<T> & FixedInstanceSet<S,T>> of the type
* FixedInstanceSet<S,T>
*/
//class NotCompiling implements FixedInstanceSet<String, NotCompiling> {
//
// #Override
// public String getKey() { return null; }
//}
If I understand you correctly, you don't want your class to be instantiated.
You can set the default constructor to private
private Key() throws IllegalStateException //handle default constructor
{
throw new IllegalStateException();
}
This will prevent its improper instantiation.
Update:
added throw IllegalStateException

Static and non static access to value

I have a class called Packet and a class called PacketClientConnecting witch extends it. The instances of PacketClientConnecting and other packets are stored in ArrayList<Packet>.
I want to have access to id value in static and non-static ways eg PacketClientConnecting.getStaticId() or packetArrayList.get(5).getId().
How can i do this without overriding two functions in every class?
I don't think there's a really smooth way of doing this, but one can achieve what you want by using reflection (only once: in the base class):
class Packet {
public static int getStaticId() {
return 1;
}
// This method is virtual and will be inherited without change
public int getId() {
try {
// Find and invoke the static method corresponding
// to the run-time instance
Method getStaticId = this.getClass().getMethod("getStaticId");
return (Integer) getStaticId.invoke(null);
// Catch three reflection-related exceptions at once, if you are on Java 7+,
// use multi-catch or just ReflectiveOperationException
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
Now in the subclass all you need is define getStaticId():
class PacketClientConnecting extends Packet {
public static int getStaticId() {
return 2;
}
}
Let's test it:
class Main {
public static void main(String[] args) {
// Both print 1
System.out.println(Packet.getStaticId());
System.out.println(new Packet().getId());
// Both print 2
System.out.println(PacketClientConnecting.getStaticId());
System.out.println(new PacketClientConnecting().getId());
}
}
If you want to avoid the overhead of calling reflective operations every time you call getId(), you can use a field in the base class to cache the id:
class Packet {
public static int getStaticId() {
return 1;
}
private final int id = computeId();
public int getId() {
return id;
}
// This method runs once per instance created
private int computeId() {
try {
Method getStaticId = this.getClass().getMethod("getStaticId");
return (Integer) getStaticId.invoke(null);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}

Categories