Closed ramiro-ciocca closed 4 years ago
Can you please paste the full exception?
Sure. Unfortunately it seems related to the Android API version in use, because it fails only for certain versions (>= Android 9)
2019-09-03 08:38:57.213 3567-3567/com.lulisoft.dreamteam E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.lulisoft.dreamteam, PID: 3567
java.lang.ExceptionInInitializerError
at com.rits.cloning.Cloner.registerFastCloners(Cloner.java:101)
at com.rits.cloning.Cloner.init(Cloner.java:88)
at com.rits.cloning.Cloner.
Ok I see, the failing Cloner method is protected so that it can be overriden:
protected void registerFastCloners() { fastCloners.put(GregorianCalendar.class, new FastClonerCalendar()); fastCloners.put(ArrayList.class, new FastClonerArrayList()); fastCloners.put(LinkedList.class, new FastClonerLinkedList()); fastCloners.put(HashSet.class, new FastClonerHashSet()); fastCloners.put(HashMap.class, new FastClonerHashMap()); fastCloners.put(TreeMap.class, new FastClonerTreeMap()); fastCloners.put(TreeSet.class, new FastClonerTreeSet()); fastCloners.put(LinkedHashMap.class, new FastClonerLinkedHashMap()); fastCloners.put(ConcurrentHashMap.class, new FastClonerConcurrentHashMap()); fastCloners.put(ConcurrentLinkedQueue.class, new FastClonerConcurrentLinkedQueue());
// register private classes
FastClonerArrayListSubList subListCloner = new FastClonerArrayListSubList();
registerInaccessibleClassToBeFastCloned("java.util.AbstractList$SubList", subListCloner);
registerInaccessibleClassToBeFastCloned("java.util.ArrayList$SubList", subListCloner);
registerInaccessibleClassToBeFastCloned("java.util.SubList", subListCloner);
registerInaccessibleClassToBeFastCloned("java.util.RandomAccessSubList", subListCloner);
}
So you can try overriding it and register only the fast cloners that work OK.
@kostaskougios :point_up_2: (got the same issue) I didn't understand what you said in above comments, so waiting for you to add this to your code ?
I have the same problem with and android app.
@RujulGandhi regarding your comment: I think he means something like this:
public class MyCloner extends Cloner { @Override protected void registerFastCloners() { // register private classes FastClonerArrayListSubList subListCloner = new FastClonerArrayListSubList(); registerInaccessibleClassToBeFastCloned("java.util.AbstractList$SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.ArrayList$SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.RandomAccessSubList", subListCloner); ... // more classes you need } }
I agree, this should be fixed within the code and should't require the user to write his own class.
Sure. Unfortunately it seems related to the Android API version in use, because it fails only for certain versions (>= Android 9)
2019-09-03 08:38:57.213 3567-3567/com.lulisoft.dreamteam E/AndroidRuntime: FATAL EXCEPTION: main Process: com.lulisoft.dreamteam, PID: 3567 java.lang.ExceptionInInitializerError at com.rits.cloning.Cloner.registerFastCloners(Cloner.java:101) at com.rits.cloning.Cloner.init(Cloner.java:88) at com.rits.cloning.Cloner.(Cloner.java:58) at com.lulisoft.dreamteam.tabPartidos.PartidoDetailCuadrosFragment.onCreate(PartidoDetailCuadrosFragment.java:144) at androidx.fragment.app.Fragment.performCreate(Fragment.java:2414) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1418) at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1195) at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1078) at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:117) at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2408) at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366) at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243) at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654) at androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146) at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244) at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669) at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631) at androidx.viewpager.widget.ViewPager.dataSetChanged(ViewPager.java:1086) at androidx.viewpager.widget.ViewPager$PagerObserver.onChanged(ViewPager.java:3097) at androidx.viewpager.widget.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:291) at com.lulisoft.dreamteam.tabPartidos.CambiosPagerAdapter.add(CambiosPagerAdapter.java:102) at com.lulisoft.dreamteam.tabPartidos.PartidoDetailDatosFragment.lambda$null$15$PartidoDetailDatosFragment(PartidoDetailDatosFragment.java:432) at com.lulisoft.dreamteam.tabPartidos.-$$Lambda$PartidoDetailDatosFragment$-Xs0Ha6cYdNtNtrmLVb8gcuCjGQ.done(Unknown Source:6) at com.lulisoft.dreamteam.tabPartidos.-$$Lambda$PartidoDetailDatosFragment$-Xs0Ha6cYdNtNtrmLVb8gcuCjGQ.done(Unknown Source:4) at com.parse.ParseTaskUtils$2$1.run(ParseTaskUtils.java:121) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6680) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) Caused by: com.rits.cloning.CloningException: java.lang.NoSuchFieldException: No field m in class Ljava/util/TreeSet; (declaration of 'java.util.TreeSet' appears in /system/framework/core-oj.jar) at com.rits.cloning.FastClonerTreeSet.(FastClonerTreeSet.java:22) at com.rits.cloning.Cloner.registerFastCloners(Cloner.java:101) at com.rits.cloning.Cloner.init(Cloner.java:88) at com.rits.cloning.Cloner.(Cloner.java:58) at com.lulisoft.dreamteam.tabPartidos.PartidoDetailCuadrosFragment.onCreate(PartidoDetailCuadrosFragment.java:144) at androidx.fragment.app.Fragment.performCreate(Fragment.java:2414) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1418) at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1195) at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1078) at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:117) at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2408) at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366) at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243) at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654) at androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146) at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244) at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669) at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631) at androidx.viewpager.widget.ViewPager.dataSetChanged(ViewPager.java:1086) at androidx.viewpager.widget.ViewPager$PagerObserver.onChanged(ViewPager.java:3097) at androidx.viewpager.widget.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:291) at com.lulisoft.dreamteam.tabPartidos.CambiosPagerAdapter.add(CambiosPagerAdapter.java:102) at com.lulisoft.dreamteam.tabPartidos.PartidoDetailDatosFragment.lambda$null$15$PartidoDetailDatosFragment(PartidoDetailDatosFragment.java:432) at com.lulisoft.dreamteam.tabPartidos.-$$Lambda$PartidoDetailDatosFragment$-Xs0Ha6cYdNtNtrmLVb8gcuCjGQ.done(Unknown Source:6) at com.lulisoft.dreamteam.tabPartidos.-$$Lambda$PartidoDetailDatosFragment$-Xs0Ha6cYdNtNtrmLVb8gcuCjGQ.done(Unknown Source:4) at com.parse.ParseTaskUtils$2$1.run(ParseTaskUtils.java:121) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6680) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) Caused by: java.lang.NoSuchFieldException: No field m in class Ljava/util/TreeSet; (declaration of 'java.util.TreeSet' appears in /system/framework/core-oj.jar) at java.lang.Class.getDeclaredField(Native Method) at com.rits.cloning.FastClonerTreeSet.(FastClonerTreeSet.java:17) at com.rits.cloning.Cloner.registerFastCloners(Cloner.java:101) at com.rits.cloning.Cloner.init(Cloner.java:88) at com.rits.cloning.Cloner.(Cloner.java:58) at com.lulisoft.dreamteam.tabPartidos.PartidoDetailCuadrosFragment.onCreate(PartidoDetailCuadrosFragment.java:144) at androidx.fragment.app.Fragment.performCreate(Fragment.java:2414) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1418) at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1195) at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1078) at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:117) at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2408) at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366) at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2243) at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:654) at androidx.fragment.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:146) at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1244) at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:669) at androidx.viewpager.widget.ViewPager.setCurrentItemInternal(ViewPager.java:631) at androidx.viewpager.widget.ViewPager.dataSetChanged(ViewPager.java:1086) at androidx.viewpager.widget.ViewPager$PagerObserver.onChanged(ViewPager.java:3097) at androidx.viewpager.widget.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:291) at com.lulisoft.dreamteam.tabPartidos.CambiosPagerAdapter.add(CambiosPagerAdapter.java:102) at com.lulisoft.dreamteam.tabPartidos.PartidoDetailDatosFragment.lambda$null$15$PartidoDetailDatosFragment(PartidoDetailDatosFragment.java:432) at com.lulisoft.dreamteam.tabPartidos.-$$Lambda$PartidoDetailDatosFragment$-Xs0Ha6cYdNtNtrmLVb8gcuCjGQ.done(Unknown Source:6) at com.lulisoft.dreamteam.tabPartidos.-$$Lambda$PartidoDetailDatosFragment$-Xs0Ha6cYdNtNtrmLVb8gcuCjGQ.done(Unknown Source:4) at com.parse.ParseTaskUtils$2$1.run(ParseTaskUtils.java:121) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6680) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
是因为反射导致的。 我认为这里不需要反射,所以去掉了就可以了
public class FastClonerTreeSet implements IFastCloner {
// private static final Field m;
// private static final Field comparator;
// static {
// try {
// m = TreeSet.class.getDeclaredField("m");
// m.setAccessible(true);
// comparator = TreeMap.class.getDeclaredField("comparator");
// comparator.setAccessible(true);
// } catch (NoSuchFieldException e) {
// throw new CloningException(e);
// }
// }
@SuppressWarnings("unchecked")
public Object clone(Object t, IDeepCloner cloner, Map<Object, Object> clones) {
// TreeSet treeSet = (TreeSet) t;
// TreeSet result = null;
// try {
// result = new TreeSet((Comparator) comparator.get(m.get(t)));
// } catch (IllegalAccessException e) {
// throw new CloningException("Failed to get the comparator from a tree set", e);
// }
// for (Object o : treeSet) {
// result.add(cloner.deepClone(o, clones));
// }
final TreeSet treeSet = (TreeSet) t;
final TreeSet result = new TreeSet(treeSet.comparator());
for(final Object o: treeSet){
result.add(cloner.deepClone(o, clones));
}
return result;
}
}
@kostaskougios That code snippet in the last comment looks right to me. I mean, as I see, the previous code is using reflection to access TreeSet.m
(which is a TreeMap
) and then Treemap.comparator
. Why not calling TreeSet.comparator()
without using reflection at all?
I tried it on my machine and the tests were running fine. Do you want to look at it yourself or do you want me to make a pull request?
That code was introduced in #85, but I cannot see a reason why @spullara would use reflection at that place. See also FastClonerTreeMap, that one accesses treeSet.comparator()
directly, without reflection.
Btw that piece of code also causes that warnung on startup.
WARNING: Illegal reflective access by com.rits.cloning.FastClonerTreeSet (file:/home/xxxx/git/cloning/target/classes/) to field java.util.TreeSet.m
@tweimer thanks for the PR, the code is in v1.10.3 which I just released
I´m having that exception for just creating a Cloner object:
Cloner cloner = new Cloner();
I'm usgin Android Studio 3.5 in a project with target sdk API 29
Thanks!