Not able to keep a class which has dynamically referenced class

HI ,
I am at the last stage of my project obfuscation but somehow its stuck in one of its error
the error is


I tried to keep this class
by below option
-keep public class pipelineprocess.components.csv.CsvWriter{;}
even I tried keep attributes of inner class as well
-keepattributes
Exceptions,
InnerClasses,
Signature,
Deprecated,
SourceFile,
LineNumberTable,
Annotation,
EnclosingMethod
-keepnames interface **
-keep
class com.ericsson.edosdp.geobox.GeoBoxMain {
public void main(java.lang.String[]);
}
-keep public class pipelineprocess.components.csv.CsvWriter{
;}

but nothing is working

let me know if u want me to attach my class details also

pasting the details of my csvwriter class as well

package pipelineprocess.components.csv;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pipelineprocess.DataObject;
import pipelineprocess.components.Transformer;
import pipelineprocess.exception.PipelineException;
import pipelineprocess.properties.ConfigurationConstants;
import pipelineprocess.utils.DataObjectUtils;
import pipelineprocess.utils.csv.CsvFile;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

public class CsvWriter extends Transformer {
private static final String HEADER_PROPERTY = “header”;
private static final String FILE_PROPERTY = “file”;
private static final String SEPARATOR_PROPERTY = “separator”;
private static final String NULL_VALUE_PROPERTY = “nullValue”;
private static final String COLUMN_INDEX_LIST_PROPERTY = “columnIndexList”;
private static final String SPLIT_FILE_PROPERTY = “splitFile”;
private static final String ADD_TIMESTAMP_PROPERTY = “addTimeStamp”;
private static final String SPLIT_TIME_PROPERTY = “splitTime”;
private static final String RECORD_NAME_PROPERTY = “recordName”;
private static final String QUOTATION_MODE_PROPERTY = “quotationMode”;
private static final String QUOTATION_MARK_PROPERTY = “quotationMark”;
private static final String ESCAPING_SEQUENCE_PROPERTY = “escapingSequence”;
private static final String QUOTED_COLUMN_INDEX_LIST_PROPERTY = “quotedColumnIndexList”;
private static final boolean DEFAULT_SPLIT_FILE = false;
private static final boolean DEFAULT_ADDTIMESTAMP = false;
private static final int DEFAULT_SPLIT_TIME = 60;
private static final String DEFAULT_SEPARATOR = “,”;
private static final String DEFAULT_QUOTATION_MARK = “”";
private static final String DEFAULT_ESCAPING_SEQUENCE = “”";
private static final QuotationMode DEFAULT_QUOTATION_MODE = QuotationMode.NONE;
private static final Logger LOGGER = LoggerFactory.getLogger(CsvWriter.class);
private static final long MILLISECONDS = 1000L;

private String nullValue = null;
private String fileName = null;
private List<Integer> columnIndexList;
private String separator = null;
private CsvFile csvOutput;
private volatile boolean closeFile = false;
private Timer timerWriter;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd_HHmmss");
private String quotationMark = DEFAULT_QUOTATION_MARK;
private String escapingSequence = DEFAULT_ESCAPING_SEQUENCE;
private List<Integer> quotedColumnIndexList;
private CsvQuoter csvQuoter;
private CsvQuoter nullQuoter;

private boolean splitFile;
private int splitTime;
private String recordName;
private String header;
private String file;
private boolean addTimeStamp;



@Override
public void init() throws PipelineException {
    separator = getProperty(SEPARATOR_PROPERTY);
    if (separator == null || separator.isEmpty()) {
        separator = DEFAULT_SEPARATOR;
    }

    nullValue = getProperty(NULL_VALUE_PROPERTY);
    columnIndexList = readIntegerListProperty(COLUMN_INDEX_LIST_PROPERTY);
    quotationMark = readStringProperty(QUOTATION_MARK_PROPERTY, DEFAULT_QUOTATION_MARK);

    QuotationMode quotationMode = QuotationMode.get(readStringProperty(QUOTATION_MODE_PROPERTY, DEFAULT_QUOTATION_MODE.name()));
    quotedColumnIndexList = readIntegerListProperty(QUOTED_COLUMN_INDEX_LIST_PROPERTY);
    escapingSequence = readStringProperty(ESCAPING_SEQUENCE_PROPERTY, DEFAULT_ESCAPING_SEQUENCE);
    csvQuoter = instantiateQuoter(quotationMode);
    nullQuoter = instantiateQuoter(DEFAULT_QUOTATION_MODE);

    splitFile = readBoolProperty(SPLIT_FILE_PROPERTY, DEFAULT_SPLIT_FILE);
    splitTime = readIntegerProperty(SPLIT_TIME_PROPERTY, DEFAULT_SPLIT_TIME);
    recordName = readStringProperty(RECORD_NAME_PROPERTY, "");
    header = getProperty(HEADER_PROPERTY);
    file = getProperty(FILE_PROPERTY);
    addTimeStamp = readBoolProperty(ADD_TIMESTAMP_PROPERTY, DEFAULT_ADDTIMESTAMP);
}

@Override
public void onDataAvailable(List<DataObject> data) throws PipelineException {
    try {
        for (DataObject obj : data) {
            List<Object> fields;
            if (!columnIndexList.isEmpty()) {
                fields = DataObjectUtils.getFields(obj, columnIndexList);
            }
            else {
                fields = obj.getAllFields();
            }
            List<String> line = processFields(fields);
            checkCsvFile();
            csvOutput.writeLine(line);
        }
    } catch (IOException e) {
        throw new PipelineException("Pipeline Exception. Cause: " + e.getMessage());
    }
}

private List<String> processFields(List<Object> fields) {
    List<String> line = new ArrayList<>(fields.size());
    for (int i = 0; i < fields.size(); ++i) {
        Object fieldValue = fields.get(i);
        if (quotedColumnIndexList.isEmpty() || quotedColumnIndexList.contains(i)) {
            line.add(i, csvQuoter.apply(fieldValue));
        } else {
            line.add(i, nullQuoter.apply(fieldValue));
        }
    }
    return line;
}

@Override
public void onStartOfStream() throws PipelineException {
    createCsvFile();
    if (splitFile && timerWriter == null) {
        timerWriter = new Timer(true);
        timerWriter.schedule(new WriterTask(), splitTime * MILLISECONDS,
                splitTime * MILLISECONDS);
    }
}

@Override
public void onEndOfStream() throws PipelineException {
    if (splitFile) {
        timerWriter.cancel();
    }
    closeCsvFile();
}

private void checkCsvFile() throws PipelineException {
    if (splitFile && closeFile) {
        closeCsvFile();
        createCsvFile();
    }
}

private void closeCsvFile() throws PipelineException {
    LOGGER.info("** CSV End {} **", this.fileName);
    if (csvOutput != null) {
        Path src = getSourceFile();
        Path tgt = getTargetFile();

        csvOutput.close();
        try {
            Files.move(src, tgt);
        } catch (IOException e) {
            LOGGER.error("** CSV unable to rename %s to %s ", src, tgt);
        }
    }
    closeFile = false;
}

@VisibleForTesting
void generateFileName() {
    fileName = getFileName();
}

private void createCsvFile() throws PipelineException {
    try {
        generateFileName();
        Path filePath = getSourceFile();
        csvOutput = new CsvFile(filePath.toFile(), separator.charAt(0), CsvFile.DEFAULT_ESCAPE_CHAR, CsvFile.DEFAULT_LINE_SEPARATOR, false);

        // write header
        if (header != null && !header.isEmpty()) {

            List<String> headerFields = Arrays.stream(header.split(","))
                    .map(String::trim)
                    .collect(Collectors.toList());
            csvOutput.writeLine(headerFields);
        }

    } catch (IOException e) {
        LOGGER.error("IOException while trying to write CSV data", e);
    }
}

private Path buildFilePath(String folder, String errorMessage) throws PipelineException {
    Preconditions.checkState(Objects.nonNull(fileName), "filename not set!");

    if (folder == null) {
        throw new PipelineException("Error in component '" + getId() + "' when creating file: " + errorMessage);
    }

    Path temporalFile = Paths.get(folder, fileName);
    if (Files.notExists(temporalFile.getParent())) {
        throw new PipelineException("ERROR! File " + temporalFile.getParent() + " doesn't exists");
    }

    return temporalFile;
}

@VisibleForTesting
Path getSourceFile() throws PipelineException {
    String temporalFolder = getPipeline().getEnvironmentProperty(ConfigurationConstants.TEMP_FOLDER_PROPERTY);
    return buildFilePath(temporalFolder, "no temporary folder defined.");
}

@VisibleForTesting
Path getTargetFile() throws PipelineException {
    String targetFolder = getPipeline().getOutputFolder();
    return buildFilePath(targetFolder, "unknown destination folder.");
}

private String getFileName() {
    if (splitFile) {
        return file.replace(recordName,
                recordName + "_" + LocalDateTime.now().format(formatter));
    } else {
        if (addTimeStamp) {
            int extPosition = file.lastIndexOf('.');
            int insertPosition = (extPosition == -1) ? file.length() : extPosition;
            String timestamp = "_" + LocalDateTime.now().format(formatter);

            return new StringBuilder(file).insert(insertPosition, timestamp).toString();
        }
    }
    return file;
}

/**
 * Task executed every configurated time in order to create csv files per x
 * time.
 */
class WriterTask extends TimerTask {
    public void run() {
        closeFile = true;
    }
}

private CsvQuoter instantiateQuoter(QuotationMode mode) throws PipelineException {
    Class<? extends CsvQuoter> quoterClass = mode.getQuoterClass();
    try {
        return quoterClass.getDeclaredConstructor(CsvWriter.class).newInstance(this);
    } catch (ReflectiveOperationException | IllegalArgumentException| SecurityException e) {
        throw new PipelineException("Could not instantiate " + quoterClass.getName(), e);
    }
}

enum QuotationMode {
    NONE(NoQuotes.class),
    ALL(AllQuotes.class),
    MINIMAL(MinimalQuotes.class),
    NONNUMERIC(NonNumericQuotes.class),
    DUMB(DumbQuotes.class);

    private final Class<? extends CsvQuoter> quoterClass;

    QuotationMode(Class<? extends CsvQuoter> quoterClass) {
        this.quoterClass = quoterClass;
    }

    Class<? extends CsvQuoter> getQuoterClass() {
        return quoterClass;
    }

    public static QuotationMode get(final String mode) {
        try {
            return valueOf(mode.trim().toUpperCase());
        } catch (IllegalArgumentException e) {
            return DEFAULT_QUOTATION_MODE;
        }
    }
}

interface CsvQuoter extends Function<Object, String> {}

abstract class AbstractCsvQuoter implements CsvQuoter {
    protected abstract String getQuoted(final @Nonnull Object field);

    public String apply(Object o) {
        return (o != null) ? getQuoted(o) : nullValue;
    }

    protected boolean isQuotingNeeded(final String text) {
        return text.contains(separator) || text.contains(quotationMark);
    }

    protected String escapeString(final String text) {
        return text.replaceAll(quotationMark, Matcher.quoteReplacement(escapingSequence + quotationMark));
    }
}

class NoQuotes extends AbstractCsvQuoter {
    @Override
    protected String getQuoted(@Nonnull Object field) {
        return DataObjectUtils.getNonNullStringValue(field);
    }
}

class AllQuotes extends AbstractCsvQuoter {
    @Override
    protected String getQuoted(@Nonnull Object field) {
        return quotationMark + escapeString(DataObjectUtils.getNonNullStringValue(field)) + quotationMark;
    }
}

class MinimalQuotes extends AbstractCsvQuoter {
    @Override
    protected String getQuoted(@Nonnull Object field) {
        String nonQuotedString = DataObjectUtils.getNonNullStringValue(field);
        if (isQuotingNeeded(nonQuotedString)) {
            return quotationMark + escapeString(nonQuotedString) + quotationMark;
        }
        else {
            return nonQuotedString;
        }
    }
}

class NonNumericQuotes extends AbstractCsvQuoter {
    @Override
    protected String getQuoted(@Nonnull Object field) {
        String nonQuotedString = DataObjectUtils.getNonNullStringValue(field);
        if (field instanceof Number) {
            return nonQuotedString;
        }
        else {
            return quotationMark + escapeString(nonQuotedString) + quotationMark;
        }
    }
}

class DumbQuotes extends AbstractCsvQuoter {
    @Override
    protected String getQuoted(@Nonnull Object field) {
        return quotationMark + DataObjectUtils.getNonNullStringValue(field) + quotationMark;
    }
}

}

@Jesse and team
i have really tried many options
please see if you can help me … I am unable to keep the whole class
half is obfuscating


the inner classes

or if you can give me the idea of obfuscating the whole class
I am unable to obfuscate the whole class…
this csvwriter should get convert in some name …
and same in my mappingxml file

Hello Shradha,

If I understand you correctly, you want to keep the entire class?
pipelineprocess.components.csv.CsvWriter

Is this understanding correct?


It looks like your private fields are being obfuscated.

To keep the class and all private fields:

    -keep class pipelineprocess.components.csv.CsvWriter {
    private <fields>;
    }

If you wish to keep everything (not just private fields)

    -keep class pipelineprocess.components.csv.CsvWriter {
    <fields>;
    }

You can also experiment with keeping specific class members.

To keep all private fields in the CsvWriter class:

    -keepclassmembers class pipelineprocess.components.csv.CsvWriter{
        private <fields>;    
    }

Protip: Try using the ProGuard Playground to experiment with -keep options. It will show you the output before you build, so you can safe time and effort constructing fine-tuned configurations!

Please let us know if anything is not clear.

Kind Regards,

Jack

2 Likes