Make sure the elements are sorted in an encoded annotation

This commit is contained in:
Ben Gruver 2015-03-16 20:36:34 -07:00 committed by Connor Tumbleson
parent 757e1dac45
commit eb3b01f318
4 changed files with 57 additions and 5 deletions

View File

@ -55,7 +55,7 @@ public interface Annotation extends BasicAnnotation, Comparable<Annotation> {
* *
* @return The type of this annotation * @return The type of this annotation
*/ */
@Nonnull String getType(); @Nonnull @Override String getType();
/** /**
* Gets a set of the name/value elements associated with this annotation. * Gets a set of the name/value elements associated with this annotation.
@ -64,7 +64,7 @@ public interface Annotation extends BasicAnnotation, Comparable<Annotation> {
* *
* @return A set of AnnotationElements * @return A set of AnnotationElements
*/ */
@Nonnull Set<? extends AnnotationElement> getElements(); @Nonnull @Override Set<? extends AnnotationElement> getElements();
/** /**
* Returns a hashcode for this Annotation. * Returns a hashcode for this Annotation.

View File

@ -572,7 +572,6 @@ public abstract class DexWriter<
} }
} }
private void writeAnnotationSets(@Nonnull DexDataWriter writer) throws IOException { private void writeAnnotationSets(@Nonnull DexDataWriter writer) throws IOException {
writer.align(); writer.align();
annotationSetSectionOffset = writer.getPosition(); annotationSetSectionOffset = writer.getPosition();

View File

@ -31,7 +31,9 @@
package org.jf.dexlib2.writer; package org.jf.dexlib2.writer;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.ValueType; import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.base.BaseAnnotationElement;
import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.MethodReference;
@ -40,7 +42,8 @@ import java.io.IOException;
import java.util.Collection; import java.util.Collection;
public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends FieldReference, public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends FieldReference,
MethodRefKey extends MethodReference, AnnotationElement, EncodedValue> { MethodRefKey extends MethodReference, AnnotationElement extends org.jf.dexlib2.iface.AnnotationElement,
EncodedValue> {
@Nonnull private final DexDataWriter writer; @Nonnull private final DexDataWriter writer;
@Nonnull private final StringSection<StringKey, ?> stringSection; @Nonnull private final StringSection<StringKey, ?> stringSection;
@Nonnull private final TypeSection<?, TypeKey, ?> typeSection; @Nonnull private final TypeSection<?, TypeKey, ?> typeSection;
@ -70,7 +73,11 @@ public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends
writer.writeEncodedValueHeader(ValueType.ANNOTATION, 0); writer.writeEncodedValueHeader(ValueType.ANNOTATION, 0);
writer.writeUleb128(typeSection.getItemIndex(annotationType)); writer.writeUleb128(typeSection.getItemIndex(annotationType));
writer.writeUleb128(elements.size()); writer.writeUleb128(elements.size());
for (AnnotationElement element: elements) {
Collection<? extends AnnotationElement> sortedElements = Ordering.from(BaseAnnotationElement.BY_NAME)
.immutableSortedCopy(elements);
for (AnnotationElement element: sortedElements) {
writer.writeUleb128(stringSection.getItemIndex(annotationSection.getElementName(element))); writer.writeUleb128(stringSection.getItemIndex(annotationSection.getElementName(element)));
writeEncodedValue(annotationSection.getElementValue(element)); writeEncodedValue(annotationSection.getElementValue(element));
} }

View File

@ -41,10 +41,12 @@ import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.AnnotationElement; import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.value.AnnotationEncodedValue;
import org.jf.dexlib2.immutable.ImmutableAnnotation; import org.jf.dexlib2.immutable.ImmutableAnnotation;
import org.jf.dexlib2.immutable.ImmutableAnnotationElement; import org.jf.dexlib2.immutable.ImmutableAnnotationElement;
import org.jf.dexlib2.immutable.ImmutableClassDef; import org.jf.dexlib2.immutable.ImmutableClassDef;
import org.jf.dexlib2.immutable.ImmutableDexFile; import org.jf.dexlib2.immutable.ImmutableDexFile;
import org.jf.dexlib2.immutable.value.ImmutableAnnotationEncodedValue;
import org.jf.dexlib2.immutable.value.ImmutableNullEncodedValue; import org.jf.dexlib2.immutable.value.ImmutableNullEncodedValue;
import org.jf.dexlib2.writer.io.MemoryDataStore; import org.jf.dexlib2.writer.io.MemoryDataStore;
import org.jf.dexlib2.writer.pool.DexPool; import org.jf.dexlib2.writer.pool.DexPool;
@ -87,4 +89,48 @@ public class DexWriterTest {
Assert.assertEquals("blah", dbElements.get(0).getName()); Assert.assertEquals("blah", dbElements.get(0).getName());
Assert.assertEquals("zabaglione", dbElements.get(1).getName()); Assert.assertEquals("zabaglione", dbElements.get(1).getName());
} }
@Test
public void testEncodedAnnotationElementOrder() {
// Elements are out of order wrt to the element name
ImmutableSet<ImmutableAnnotationElement> encodedElements =
ImmutableSet.of(new ImmutableAnnotationElement("zabaglione", ImmutableNullEncodedValue.INSTANCE),
new ImmutableAnnotationElement("blah", ImmutableNullEncodedValue.INSTANCE));
ImmutableAnnotationEncodedValue encodedAnnotations =
new ImmutableAnnotationEncodedValue("Lan/encoded/annotation", encodedElements);
ImmutableSet<ImmutableAnnotationElement> elements =
ImmutableSet.of(new ImmutableAnnotationElement("encoded_annotation", encodedAnnotations));
ImmutableAnnotation annotation = new ImmutableAnnotation(AnnotationVisibility.RUNTIME,
"Lorg/test/anno;", elements);
ImmutableClassDef classDef = new ImmutableClassDef("Lorg/test/blah;",
0, "Ljava/lang/Object;", null, null, ImmutableSet.of(annotation), null, null);
MemoryDataStore dataStore = new MemoryDataStore();
try {
DexPool.writeTo(dataStore, new ImmutableDexFile(ImmutableSet.of(classDef)));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dataStore.getData());
ClassDef dbClassDef = Iterables.getFirst(dexFile.getClasses(), null);
Assert.assertNotNull(dbClassDef);
Annotation dbAnnotation = Iterables.getFirst(dbClassDef.getAnnotations(), null);
Assert.assertNotNull(dbAnnotation);
AnnotationElement element = Iterables.getFirst(dbAnnotation.getElements(), null);
AnnotationEncodedValue dbAnnotationEncodedValue = (AnnotationEncodedValue)element.getValue();
List<AnnotationElement> dbElements = Lists.newArrayList(dbAnnotationEncodedValue.getElements());
// Ensure that the elements were written out in sorted order
Assert.assertEquals(2, dbElements.size());
Assert.assertEquals("blah", dbElements.get(0).getName());
Assert.assertEquals("zabaglione", dbElements.get(1).getName());
}
} }