-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feature] copying JCodeModel #94
Comments
That means a deep-copy of all objects and expressions... That's going to be a big one |
yes. |
Okay, than can we have quick chat on how to do it? |
I'll make a branch. I was more asking if there is a visible impossibility for this, as to avoid doing "a big one" for nothing. The method in JCodemodel is just copy(), the ModelCopy extends JCodemodel and add various translate(..) to get the translation. |
One thing that strikes me, is that the basic types (like VOID or BOOLEAN) depend on the JCodeModel instance and all usages of those must also be transfered. That means that the new CM must be passed through quite deep |
The issue I have, is that some constructor eg Jatom() are protected. |
Just make them public. Or create factory methods |
NAh I put my ModelCopy in the same package. The less modifications, the better. |
I though you add a copy-constructor or clone method in every class? |
yes, I just add one class that makes the copy in itself. |
Ah okay. But isnt't there a certain danger that you forget stuff? |
indeed. |
Than maybe for the expression stuff could you go for a solution like this: ead1645 |
No, because we need to translate all references . |
Okay, and what if |
They must be able to translate their internal fields too. So they need to be getClone(ModelCopy). |
Reflection makes it even more difficult, especially if some byte code modifying frameworks like ByteBuddy or the Spring stuff is used, you might get weird errors. I would really prefer a clean, explicit way. Ideally with the respective code in each class separately. There are not too many derivations. What could be an issue is the order of cloning of classes - because the references between created classes can only be copied properly, if the order is maintained. Maybe a separate "creationOrder" field is needed for classes? |
anyhow reflect can't be used since there is no empty constructor. Not sure what you mean about issue of cloning classes. I cache the classes, when the class is missing I create it, cache it, then start building it. So there should not be a recursion issue. I try to avoid making weird stuff in other classes, like creating code that is not necessarily relevant. If later the cloning costs too much dev time, we can just deprecate it ? I try to throw exceptions when I can to tell that a case is not caught. |
Okay - that sounds like a fair compromise. I like throwing exceptions :) |
I had to add
in JreferencedClass, it had no public access. |
Such getters are always great. This is one of the big differences of this project to the original codemodel. If you find more of those - just add them. |
I did part of the translation of types. Still a lot to do ^^ I use instanceof when I know the delegated method makes a hard check on the sub types, getClass()== when checking for a specific type to generate. This way if classes are added exception will be thrown. |
Another issue I got along is the caching of elements. I started by only caching the classes, for a deep copying recursive issue (what if a field refer to the class being copied ?) . But then I realized another issue. Basically we want two things for the copying from a SRC model to a CP model:
The first part implies to copy everything, even the JAtom. |
basically the translate(parametertype source) code is following :
Then the "tree" of the method starts with interface IJObject, and create the whole interface subclasses translates (therefore only instanceof ) . Then another part of code is for each abstract class, becaue abstract classes belong to a tree (no diamond like interfaces) then I can create a tree from the highest non interface class that implement IJObject. |
Here I show how it is with the caching. What remains is … well every todo ^^ |
yes, to build the same structure you somehow need a state that know about all objects and if they are already cloned or not. So I think coming back to a |
cloneState is the ModelCopy class. I think you are right, that Serializable would be faster, more bug proof. But I'm not sure how it would handle the cases of static instances. Also I still need to have the translate() method, that translates an item from the source model into the copy model. Also : In order to test the copy() method, I need to have a way to convert the model into a string (or at least a comparable item) . Do you think there is already such a method I could use ? Typically the test would be (pseudo code) cm=createCM();
copy = cm.copy();
assertEquals(cm.representString(), copy.representString());
for(Consumer<Model> m : modifications) {
m.accept(cm);
assertNotEquals(cm.representString, copy.representString);
}
for(Consumer<Model> m : modifications) {
m.accept(copy);
}
assertEquals(cm.representString, copy.representString); |
java code for the test. The interesting part is that it can be subclassed to test various implementations of copy and represent. Obviously it will fail with the toString() and return source; implementations ^^ public class ModelCopyTest
{
@Test
public void testCopy ()
{
JCodeModel cm = createCM ();
JCodeModel copy = copy (cm);
Assert.assertEquals (represent (cm), represent (copy));
for (Consumer <JCodeModel> m : modifications ())
{
m.accept (cm);
Assert.assertNotEquals (represent (cm), represent (copy));
}
for (Consumer <JCodeModel> m : modifications ())
m.accept (copy);
Assert.assertEquals (represent (cm), represent (copy));
}
JCodeModel createCM ()
{
JCodeModel ret = new JCodeModel ();
return ret;
}
JCodeModel copy (JCodeModel source)
{
return source;
}
String represent (JCodeModel target)
{
return target.toString ();
}
public Collection <Consumer <JCodeModel>> modifications ()
{
return Arrays.asList (cm ->
{
try
{
cm._class (JMod.PUBLIC, "MyClass");
}
catch (JCodeModelException e)
{
throw new UnsupportedOperationException ("catch this", e);
}
});
}
} |
In last patch I made that method abstract, and made a simple implementation with serialization to copy ; and a new StringCodeWriter extends AbstractCodeWriter for which toString() return the whole content of the files created from a JCMWriter.build(), appended with the name of the file to start. When I try to make a more complex model, I get this error : |
I added serializable on a few classes. this patch guiguilechat@682f0ef |
is the abstract method. As you can see the creation of the cm is pretty simple. Do you have a CM created by other tests that is more complex ? The goal is just to test the copying, so a JCM that contains as much possibility as possible would be good. This class |
I lost the link between a source item (say JDefined class) and it translated version but it's much simpler. MUCH simpler. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
I propose to add a new method in JCodeModel : copy().
This method returns a new CopiedModel that contains recursive copy of all the elements of the parent model.
This CopiedModel also allows to translate the elements of the parent model into its own elements.
This method could be used with the preprocessors : instead of working on the original model, processors would be applied on the copy. If no processor is used, then no copy is done.
Working on it.
The text was updated successfully, but these errors were encountered: