Skip to content
This repository was archived by the owner on May 26, 2018. It is now read-only.

Commit 2cca7aa

Browse files
committedMay 8, 2013
Some more Scala @SidedProxy adjustments. Now properly supporting pure singletons, i.e.
object C { @SidedProxy(...) var proxy: P = null } Removed fallback, as all such singletons are properly handled by the new code now, and class implementations fall back to the code also used for plain Java mods.
1 parent 23b070c commit 2cca7aa

File tree

2 files changed

+113
-17
lines changed

2 files changed

+113
-17
lines changed
 

Diff for: ‎common/cpw/mods/fml/common/ILanguageAdapter.java

+110-17
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
import java.lang.reflect.Field;
44
import java.lang.reflect.InvocationTargetException;
55
import java.lang.reflect.Method;
6+
import java.util.logging.Level;
7+
8+
import cpw.mods.fml.common.Mod.Instance;
9+
import cpw.mods.fml.relauncher.Side;
610

711
public interface ILanguageAdapter {
812
public Object getNewInstance(FMLModContainer container, Class<?> objectClass, ClassLoader classLoader) throws Exception;
913
public boolean supportsStatics();
1014
public void setProxy(Field target, Class<?> proxyTarget, Object proxy) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException;
15+
public void setInternalProxies(ModContainer mod, Side side, ClassLoader loader);
1116

1217
public static class ScalaAdapter implements ILanguageAdapter {
1318
@Override
@@ -26,22 +31,47 @@ public boolean supportsStatics()
2631
@Override
2732
public void setProxy(Field target, Class<?> proxyTarget, Object proxy) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException
2833
{
34+
Object targetInstance;
35+
2936
try
3037
{
31-
// Check if the target class is a singleton, if so its
32-
// implementation's class name is the actual classname
33-
// postfixed with a $.
34-
final Class<?> targetSingleton = Class.forName(proxyTarget.getName() + "$", true, proxyTarget.getClassLoader());
38+
// Get the actual singleton class. The two variants are from
39+
// whether the @SidedProxy is declared in a the class block
40+
// of the object directly, or in the object block, i.e.
41+
// whether it's:
42+
// class ModName {
43+
// @SidedProxy ...
44+
// }
45+
// object ModName extends ModName {}
46+
// which leads to us getting the outer class, or
47+
// object ModName {
48+
// @SidedProxy ...
49+
// }
50+
// which leads to us getting the inner class.
51+
if (!proxyTarget.getName().endsWith("$"))
52+
{
53+
// Get internal class generated by Scala.
54+
proxyTarget = Class.forName(proxyTarget.getName() + "$", true, proxyTarget.getClassLoader());
55+
}
3556

3657
// Get the instance via the MODULE$ field which is
37-
// automatically generated by the scala compiler for
58+
// automatically generated by the Scala compiler for
3859
// singletons.
39-
final Object targetInstance = targetSingleton.getField("MODULE$").get(null);
60+
targetInstance = proxyTarget.getField("MODULE$").get(null);
61+
}
62+
catch (ClassNotFoundException e)
63+
{
64+
// Not a singleton, look for @Instance field as a fallback.
65+
FMLLog.log(Level.SEVERE, e, "An error occured trying to load a proxy into %s.%s. Did you declare your mod as 'class' instead of 'object'?", proxyTarget.getSimpleName(), target.getName());
66+
throw new LoaderException(e);
67+
}
4068

69+
try
70+
{
4171
// Find setter function. We do it this way because we can't
4272
// necessarily use proxyTarget.getMethod(proxy.getClass()), as
4373
// it might be a subclass and not the exact parameter type.
44-
// All fields are private in scala, wrapped by a getter and
74+
// All fields are private in Scala, wrapped by a getter and
4575
// setter named <fieldname> and <fieldname>_$eq. To those
4676
// familiar with scala.reflect.BeanProperty: these will always
4777
// be there, set<Fieldname> and get<Fieldname> will always
@@ -55,27 +85,84 @@ public void setProxy(Field target, Class<?> proxyTarget, Object proxy) throws Il
5585
setterParameters.length == 1 &&
5686
setterParameters[0].isAssignableFrom(proxy.getClass()))
5787
{
58-
// Here goes nothing... if this invocation fails we'll
59-
// just fall back to the original functionality.
88+
// Here goes nothing...
6089
setter.invoke(targetInstance, proxy);
6190
return;
6291
}
6392
}
6493
}
65-
catch (ClassNotFoundException e)
66-
{
67-
FMLLog.fine("This scala class is not a singleton (scala object), falling back to old proxy setter.");
68-
}
6994
catch (InvocationTargetException e)
7095
{
71-
FMLLog.fine("There's a problem with this proxy's setter, falling back to old proxy setter.");
96+
FMLLog.log(Level.SEVERE, e, "An error occured trying to load a proxy into %s.%s", proxyTarget.getSimpleName(), target.getName());
97+
throw new LoaderException(e);
7298
}
7399

74-
Field field = proxyTarget.getField("INSTANCE");
75-
Object scalaObject = field.get(null);
76-
target.set(scalaObject, proxy);
100+
// If we come here we could not find a setter for this proxy.
101+
FMLLog.severe("Failed loading proxy into %s.%s, could not find setter function. Did you declare the field with 'val' instead of 'var'?", proxyTarget.getSimpleName(), target.getName());
102+
throw new LoaderException();
103+
}
104+
105+
@Override
106+
public void setInternalProxies(ModContainer mod, Side side, ClassLoader loader)
107+
{
108+
// For Scala mods, we want to enable authors to write them like so:
109+
// object ModName {
110+
// @SidedProxy(...)
111+
// var proxy: ModProxy = null
112+
// }
113+
// For this to work, we have to search inside the inner class Scala
114+
// generates for singletons, which is in called ModName$. These are
115+
// not automatically handled, because the mod discovery code ignores
116+
// internal classes.
117+
// Note that it is alternatively possible to write this like so:
118+
// class ModName {
119+
// @SidedProxy(...)
120+
// var proxy: ModProxy = null
121+
// }
122+
// object ModName extends ModName { ... }
123+
// which will fall back to the normal injection code which calls
124+
// setProxy in turn.
125+
126+
// Get the actual mod implementation, which will be the inner class
127+
// if we have a singleton.
128+
Class<?> proxyTarget = mod.getMod().getClass();
129+
if (proxyTarget.getName().endsWith("$"))
130+
{
131+
// So we have a singleton class, check if there are targets.
132+
for (Field target : proxyTarget.getDeclaredFields())
133+
{
134+
// This will not turn up anything if the alternative
135+
// approach was taken (manually declaring the class).
136+
// So we don't initialize the field twice.
137+
if (target.getAnnotation(SidedProxy.class) != null)
138+
{
139+
String targetType = side.isClient() ? target.getAnnotation(SidedProxy.class).clientSide() : target.getAnnotation(SidedProxy.class).serverSide();
140+
try
141+
{
142+
Object proxy = Class.forName(targetType, true, loader).newInstance();
143+
144+
if (!target.getType().isAssignableFrom(proxy.getClass()))
145+
{
146+
FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, proxyTarget.getSimpleName(), target.getName());
147+
throw new LoaderException();
148+
}
149+
150+
setProxy(target, proxyTarget, proxy);
151+
}
152+
catch (Exception e) {
153+
FMLLog.log(Level.SEVERE, e, "An error occured trying to load a proxy into %s.%s", proxyTarget.getSimpleName(), target.getName());
154+
throw new LoaderException(e);
155+
}
156+
}
157+
}
158+
}
159+
else
160+
{
161+
FMLLog.finer("Mod does not appear to be a singleton.");
162+
}
77163
}
78164
}
165+
79166
public static class JavaAdapter implements ILanguageAdapter {
80167
@Override
81168
public Object getNewInstance(FMLModContainer container, Class<?> objectClass, ClassLoader classLoader) throws Exception
@@ -95,5 +182,11 @@ public void setProxy(Field target, Class<?> proxyTarget, Object proxy) throws Il
95182
{
96183
target.set(null, proxy);
97184
}
185+
186+
@Override
187+
public void setInternalProxies(ModContainer mod, Side side, ClassLoader loader)
188+
{
189+
// Nothing to do here.
190+
}
98191
}
99192
}

Diff for: ‎common/cpw/mods/fml/common/ProxyInjector.java

+3
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,8 @@ public static void inject(ModContainer mod, ASMDataTable data, Side side, ILangu
6767
throw new LoaderException(e);
6868
}
6969
}
70+
71+
// Allow language specific proxy injection.
72+
languageAdapter.setInternalProxies(mod, side, mcl);
7073
}
7174
}

0 commit comments

Comments
 (0)
This repository has been archived.