Obfuscate Parcelable classes with proguard - java

I'm trying to obfuscate a parcelable class with Proguard:
Before adding the Parcelable part the class is:
public class Foo{
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
The obfuscated result is:
public class a
{
private String a;
public String a()
{
return this.a;
}
public void a(String paramString)
{
this.a = paramString;
}
}
After adding implementing parcelable the example class is
public class Foo implements Parcelable {
private String value;
private Foo(Parcel in) {
value = in.readString();
}
public Foo() {
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(value);
}
public static final Parcelable.Creator<Foo> CREATOR
= new Parcelable.Creator<Foo>() {
public Foo createFromParcel(Parcel in) {
return new Foo(in);
}
public Foo[] newArray(int size) {
return new Foo[size];
}
};
}
The obfuscated result is
public class Foo implements Parcelable {
public static final Parcelable.Creator CREATOR = new a();
private String a;
public Foo() {
}
private Foo(Parcel paramParcel) {
this.a = paramParcel.readString();
}
public String a() {
return this.a;
}
public void a(String paramString) {
this.a = paramString;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel paramParcel, int paramInt) {
paramParcel.writeString(this.a);
}
}
class a implements Parcelable.Creator {
public Foo a(Parcel paramParcel) {
return new Foo(paramParcel, null);
}
public Foo[] a(int paramInt) {
return new Foo[paramInt];
}
}
How can I configure proguard for obfuscate the whole class (including name, params and methods) except the parcelable part?
Thanks

Try putting this in your proguard.cfg file:
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
That should preserve Parcelable part and obfuscate everything else.

Related

ClassCastException while using generics in java

I am new to java programming and I am learning generics.I tried to do some generics program by myself and I am getting Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.ashwin.model.Car;.
I have a Vehicle Class:
public class Vehicle {
private int id;
private String name;
private String color;
private int plateNo;
//omitted getters and setters
}
I have a Car class extending Vehicle Class.
public class Car extends Vehicle {
public Car(int id, String name, String color, int plateNo) {
super.setId(id);
super.setColor(color);
super.setPlateNo(plateNo);
}
}
I have CarDAOImpl.java class:
public class CarDAOImpl implements VehicleDAO<Car> {
private static ParkingLot<Car> park=new ParkingLot<Car>(10);
#Override
public boolean insert(Car v) {
if(park.getSpace()==-1) {
return false;
}
else {
park.setSpace(park.getSpace()-1);
park.setVehicle(v);
return true;
}
}
#Override
public boolean delete(Car k) {
if(park.getSpace()==10) {
return false;
}
else {
boolean result=park.deleteVehicle(k);
return result;
}
}
#Override
public Car[] getAll() {
return park.getVehicle();
}
}
I have another ParkingLot.java class:
public class ParkingLot<T> {
private int space;
private T[] vehicle;
public ParkingLot() {
}
public ParkingLot(int sp) {
this.vehicle=(T[])new Object[sp];
this.space=sp;
}
public int getSpace() {
return space;
}
public void setSpace(int space) {
this.space = space;
}
public T[] getVehicle() {
return vehicle;
}
public void setVehicle(T vehicle) {
this.vehicle[space]=vehicle;
}
public <T extends Vehicle> boolean deleteVehicle(T v) {
for(int i=0;i<vehicle.length;i++) {
if(((Vehicle) vehicle[i]).getId()==v.getId()) {
vehicle[i]=null;
return true;
}
}
return false;
}
}
My main method is:
public class Main {
public static void main(String[] args) {
VehicleDAO<Car> v=new CarDAOImpl();
boolean inserted=v.insert(new Car(1,"ford","Red",1234));
System.out.println(inserted);
Car[] c=v.getAll();
for(int i=0;i<c.length;i++)
{
System.out.println(c[i]);
}
}
}
I am getting error at this line of CarDAOImpl.java class:
#Override
public Car[] getAll() {
return park.getVehicle();
}
The exception is:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.ashwin.model.Car;
You need to update your constructor to include the class object as a parameter:
public ParkingLot(Class<T> clazz, int sp) {
this.vehicle= (T[]) Array.newInstance(clazz, sp);
this.space=sp;
}
And your variable declaration should look like this:
private static ParkingLot<Car> park = new ParkingLot<>(Car.class, 10);

How print the entire data structure created with Composite?

I have class-Composite:
public class CompositeText implements ComponentText {
private TypeComponent type;
private String value;
private final List<ComponentText> childComponents;
private CompositeText() {
childComponents = new ArrayList<>();
}
public CompositeText(String value, TypeComponent typeComponent) {
this.value = value;
this.type = typeComponent;
childComponents = new ArrayList<>();
}
#Override
public void add(ComponentText componentText) {
childComponents.add(componentText);
}
#Override
public void remove(ComponentText componentText) {
childComponents.remove(componentText);
}
#Override
public TypeComponent getComponentType() {
return this.type;
}
#Override
public ComponentText getChild(int index) {
return childComponents.get(index);
}
#Override
public int getCountChildElements() {
return childComponents.size();
}
#Override
public int getCountAllElements() {
return childComponents.stream()
.mapToInt(ComponentText::getCountAllElements)
.sum();
}
#Override
public String toString() {
return null;
}
}
I created classes that perform the same action - parsing, parsing text into paragraphs, into sentences, into tokens, into symbols.
public class IntoParagraphParser implements ActionParser {
// call IntoSentenceParser
}
public class IntoSentenceParser implements ActionParser {
// call IntoLexemeParser
}
public class IntoLexemeParser implements ActionParser {
// call IntoSymbolParser
}
public class IntoSymbolParser implements ActionParser {
}
All data is stored in List <ComponentText> childComponents in class-Composite - CompositeText.
How to properly create a method so that it prints all the data that is inside the composite?
I think this will be the method toString() in CompositeText.
Class IntoParagraphParser look:
public class IntoParagraphParser implements ActionParser {
private static final String PARAGRAPH_SPLIT_REGEX = "(?m)(?=^\\s{4})";
private static final IntoParagraphParser paragraphParser = new IntoParagraphParser();
private static final IntoSentenceParser sentenceParser = IntoSentenceParser.getInstance();
private IntoParagraphParser() {
}
public static IntoParagraphParser getInstance() {
return paragraphParser;
}
public ComponentText parse(String text) throws TextException {
ComponentText oneParagraph;
ComponentText componentParagraph = new CompositeText(text, TypeComponent.PARAGRAPH);
String[] arrayParagraph = text.split(PARAGRAPH_SPLIT_REGEX);
for(String element: arrayParagraph) {
oneParagraph = new CompositeText(element, TypeComponent.PARAGRAPH);
oneParagraph.add(sentenceParser.parse(element));
componentParagraph.add(oneParagraph);
}
return componentParagraph;
}
}
Need #Override the method toString() in CompositeText like this:
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (ComponentText component : childComponents) {
builder.append(component.toString());
}
return builder.toString();
}
But how to write this code correctly with Stream API?
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
childComponents.stream().map(...????
return builder.toString();
}

Java builder pattern with non-trivial subclass tree

I'm familiar with using the builder pattern with generics and subclassing, but I can't see how to make it work with a non-trivial tree of subclasses (i.e. C extends B extends A). Here's a simple example of what I'm trying to do:
class A {
private final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() { return value; }
public static class ABuilder<T extends ABuilder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T) this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static BBuilder builder() {
return new BBuilder();
}
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() { return name; }
public static class BBuilder<U extends BBuilder<U>> extends ABuilder<BBuilder<U>> {
private String name;
public U withName(String name) {
this.name = name;
return (U) this;
}
public B build() {
return new B(this);
}
}
}
Everything is fine if I declare BBuilder without the generic type:
public static class BBuilder extends ABuilder<BBuilder>
Since I want BBuilder to be extended by a CBuilder, I'm trying to use the same sort of Curiously Recurring Template Pattern as ABuilder. But like this, the compiler sees BBuilder.withValue() as returning an ABuilder, not a BBuilder as I want. This:
B b = builder.withValue(1)
.withName("X")
.build();
doesn't compile. Can anyone see what I'm doing wrong here, I've been going round trying different patterns of generics but can't get it to work.
Thanks to anyone who has any advice.
It seems that your mistake only with declaring correct parameter:
class A {
private final int value;
public static <T extends Builder<T>> T builderA() {
return (T)new Builder<>();
}
protected A(Builder<? extends Builder<?>> builder) {
value = builder.value;
}
public static class Builder<T extends Builder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T)this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static <T extends Builder<T>> T builderB() {
return (T)new Builder<>();
}
protected B(Builder<? extends Builder<?>> builder) {
super(builder);
name = builder.name;
}
public static class Builder<T extends Builder<T>> extends A.Builder<T> {
private String name;
public Builder<T> withName(String name) {
this.name = name;
return this;
}
public B build() {
return new B(this);
}
}
}
Client code:
A a = A.builder().withValue(1).build();
B b = B.builder().withValue(2).withName("xx").build();
Are you certain you need generics? This hierarchy seems to work fine without generics.
static class A {
protected final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return "A{" +
"value=" + value +
'}';
}
public static ABuilder builder() {
return new ABuilder();
}
public static class ABuilder {
protected int value;
public ABuilder withValue(int value) {
this.value = value;
return this;
}
public A build() {
return new A(this);
}
}
}
static class B extends A {
protected final String name;
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "B{" +
"value=" + value +
", name='" + name + '\'' +
'}';
}
public static BBuilder builder() {
return new BBuilder();
}
public static class BBuilder extends ABuilder {
private String name;
public BBuilder withName(String name) {
this.name = name;
return this;
}
#Override
public BBuilder withValue(int value) {
this.value = value * 2;
return this;
}
public B build() {
return new B(this);
}
}
}
static class C extends B {
private final String otherName;
protected C(CBuilder builder) {
super(builder);
this.otherName = builder.otherName;
}
public String getName() {
return otherName;
}
#Override
public String toString() {
return "C{" +
"value=" + value +
", name='" + name + '\'' +
", otherName='" + otherName + '\'' +
'}';
}
public static CBuilder builder() {
return new CBuilder();
}
public static class CBuilder extends BBuilder {
private String otherName;
public CBuilder withName(String name) {
this.otherName = name;
return this;
}
public C build() {
return new C(this);
}
}
}
public void test() {
A a = A.builder().withValue(10).build();
B b = B.builder().withValue(10).withName("B").build();
C c = C.builder().withName("C").build();
System.out.println("a = "+a);
System.out.println("b = "+b);
System.out.println("c = "+c);
}

Realm and Expected BEGIN_OBJECT but was NUMBER at path $[0].location.coordinates[0]

I'm trying to store a coordnates (array of double) using Realm-java,but I'm not able to do it.
Here is an example of json that I'm trying to parse:
{"_id":"597cd98b3af0b6315576d717",
"comarca":"string",
"font":null,
"imatge":"string",
"location":{
"coordinates":[41.64642,1.1393],
"type":"Point"
},
"marca":"string",
"municipi":"string",
"publisher":"string",
"recursurl":"string",
"tematica":"string",
"titol":"string"
}
My global object code is like that
public class Images extends RealmObject implements Serializable {
#PrimaryKey
private String _id;
private String recursurl;
private String titol;
private String municipi;
private String comarca;
private String marca;
private String imatge;
#Nullable
private Location location;
private String tematica;
private String font;
private String parentRoute;
public Location getLocation() {return location;}
public void setLocation(Location location) {this.location = location;}
public String getParentRoute() {
return parentRoute;
}
public void setParentRoute(String parentRoute) {
this.parentRoute = parentRoute;
}
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getFont() {
return font;
}
public void setFont(String font) {
this.font = font;
}
public String getRecursurl() {
return recursurl;
}
public void setRecursurl(String recursurl) {
this.recursurl = recursurl;
}
public String getTitol() {
return titol;
}
public void setTitol(String titol) {
this.titol = titol;
}
public String getMunicipi() {
return municipi;
}
public void setMunicipi(String municipi) {
this.municipi = municipi;
}
public String getComarca() {
return comarca;
}
public void setComarca(String comarca) {
this.comarca = comarca;
}
public String getMarca() {
return marca;
}
public void setMarca(String marca) {
this.marca = marca;
}
public String getImatge() {
return imatge;
}
public void setImatge(String imatge) {
this.imatge = imatge;
}
public String getTematica() {
return tematica;
}
public void setTematica(String tematica) {
this.tematica = tematica;
}
And Location is a composite of type and a realmlist
Location.java
public class Location extends RealmObject implements Serializable {
private String type;
private RealmList<RealmDoubleObject> coordinates;
public Location() {
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public RealmList<RealmDoubleObject> getCoordinates() {
return coordinates;
}
public void setCoordinates(RealmList<RealmDoubleObject> coordinates) {
this.coordinates = coordinates;
}
}
RealmDoubleObject.java
public class RealmDoubleObject extends RealmObject implements Serializable{
private Double value;
public RealmDoubleObject() {
}
public Double getDoublevalue() {
return value;
}
public void setDoublevalue(Double value) {
this.value = value;
}
}
The error is com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at path $[0].location.coordinates[0] but I'm not able to figure out why this number is not "fitting" by RealmDoubleObject.
For those that not familiar with realm RealmList doesn't work and you have to build your own realm object.
Thank you. I hope to find some Realm experts here!
SOLVED:
using Gson deserializer it can be done
First we have to initialize the gson object like this
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.registerTypeAdapter(new TypeToken<RealmList<RealmDoubleObject>>() {}.getType(), new TypeAdapter<RealmList<RealmDoubleObject>>() {
#Override
public void write(JsonWriter out, RealmList<RealmDoubleObject> value) throws IOException {
// Ignore
}
#Override
public RealmList<RealmDoubleObject> read(JsonReader in) throws IOException {
RealmList<RealmDoubleObject> list = new RealmList<RealmDoubleObject>();
in.beginArray();
while (in.hasNext()) {
Double valor = in.nextDouble();
list.add(new RealmDoubleObject(valor));
}
in.endArray();
return list;
}
})
.create();
And then we have to put some other constructor method
public RealmDoubleObject(double v) {
this.value = v;
}
and this is all.
Thanks for the help #EpicPandaForce

Abstract class as parcelable

Basicly I have the following structure in my app:
It would be straightforward to implement such a structure without the abstract class ProjectItem, but in this case I don't know how to implement this.
The abstract class ProjectItem needs a CREATOR as it should be parcelable. (like
in.readTypedList(mProjectItems, ProjectItem.CREATOR); within the constructor Project(Parcel in))
But in fact, the CREATOR can only be implemented in its derived classes for logical reasons.
So, how to implement this structure in order to keep the class Project parcelable??
Edit
This is what one of the constructors of Project looks like:
private Project(Parcel in) {
in.readTypedList(mProjectItems, ProjectItem.CREATOR);
}
But as I already said, ProjectItem shouldn't have to implement a CREATOR
My solution is similar to evertvandenbruel's. But I identify the concrete class using an int so that I can use a switch block. I also have that switch block in a static getConcreteClass(Parcel) method.
AbstractClass.java
public abstract class AbstractClass implements Parcelable {
public static final int CLASS_TYPE_ONE = 1;
public static final int CLASS_TYPE_TWO = 2;
public static final Creator<AbstractClass> CREATOR = new Creator<AbstractClass>() {
#Override
public AbstractClass createFromParcel(Parcel source) {
return AbstractClass.getConcreteClass(source);
}
#Override
public AbstractClass[] newArray(int size) {
return new AbstractClass[size];
}
};
protected String mAbstractClassString;
public AbstractClass(String abstractClassString) {
mAbstractClassString = abstractClassString;
}
public AbstractClass(Parcel source) {
mAbstractClassString = source.readString();
}
public static AbstractClass getConcreteClass(Parcel source) {
switch (source.readInt()) {
case CLASS_TYPE_ONE:
return new ConcreteClassOne(source);
case CLASS_TYPE_TWO:
return new ConcreteClassTwo(source);
default:
return null;
}
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mAbstractClassString);
}
#Override
public String toString() {
return "Parent String: " + mAbstractClassString + '\n';
}
}
ConcreteClassOne.java
public class ConcreteClassOne extends AbstractClass {
private String mString;
public ConcreteClassOne(String abstractClassMemberString, String string) {
super(abstractClassMemberString);
mString = string;
}
public ConcreteClassOne(Parcel source) {
super(source);
mString = source.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(CLASS_TYPE_ONE);
super.writeToParcel(dest, flags);
dest.writeString(mString);
}
#Override
public String toString() {
return super.toString().concat("Child String: " + mString);
}
}
ConcreteClassTwo.java
public class ConcreteClassTwo extends AbstractClass {
private String mString;
private int mInt;
public ConcreteClassTwo(String abstractClassString, String string, int anInt) {
super(abstractClassString);
mString = string;
mInt = anInt;
}
public ConcreteClassTwo(Parcel source) {
super(source);
mString = source.readString();
mInt = source.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(CLASS_TYPE_TWO);
super.writeToParcel(dest, flags);
dest.writeString(mString);
dest.writeInt(mInt);
}
#Override
public String toString() {
String string = super.toString();
for (int i = 0; i < mInt; i++) {
string = string.concat("Child String: " + mString + '\n');
}
return string;
}
}
The selected answer (from evertvandenbruel's post) has a bug in it. The correct code must account for parceling when just one of the subclasses is being parceled, not just a list of the superclass objects.
All the other code should be the same, the key is that you MUST read in the type variable in ALL creators (see code below). Otherwise there will be issues with the ordering when trying to unparcel a subclass object
Ex:
package com.example.parcelable_example.model;
import android.os.Parcel;
import android.os.Parcelable;
public class Cat extends Animal{
public Cat(String name){
super(name, "Cat");
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getType());
super.writeToParcel(dest, flags);
}
public Cat(Parcel source) {
super(source);
}
public static final Parcelable.Creator<Cat> CREATOR = new Parcelable.Creator<Cat>() {
public Cat createFromParcel(Parcel in) {
/** DO NOT FORGET THIS!!! **/
type = in.readString();
return new Cat(in);
}
public Cat[] newArray(int size) {
return new Cat[size];
}
};
}
This question arises from a false assumption.
Here is a quote from the original post.
The abstract class ProjectItem needs a CREATOR as it should be
parcelable.
In fact, It is not necessary for the super class to define CREATOR since it is abstract.
Here is a minimal example which demonstrates the method.
/* Super class */
abstract class SuperClass
implements Parcelable {
protected SuperClass(Parcel in) {
mSuperId = in.readLong();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mSuperId);
}
}
/* Sub class */
public class SubClass
extends SuperClass {
protected SubClass(Parcel in) {
super(in);
mSubId = in.readLong();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeLong(mSubId);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<SubClass> CREATOR = new Creator<SubClass>() {
#Override
public SubClass createFromParcel(Parcel in) {
return new SubClass(in);
}
#Override
public SubClass[] newArray(int size) {
return new SubClass[size];
}
};
}
/* Usage */
class AnotherClass {
void aMethod() {
Bundle args = new Bundle();
args.putParcelable("EXTRA_SUPER_CLASS", subClassObject);
}
}
public abstract class A implements Parcelable {
private int a;
protected A(int a) {
this.a = a;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(a);
}
protected A(Parcel in) {
a = in.readInt();
}
}
public class B extends A {
private int b;
public B(int a, int b) {
super(a);
this.b = b;
}
public static final Parcelable.Creator<B> CREATOR = new Parcelable.Creator<B>() {
public B createFromParcel(Parcel in) {
return new B(in);
}
public B[] newArray(int size) {
return new B[size];
}
};
public int describeContents() {
return 0;
}
}

Categories