    @Override
    public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException {
        FlowFile flowFile = session.get();
        if (flowFile == null) {
            return;
        }

        final String projectId = context.getProperty(PROJECT_ID).evaluateAttributeExpressions().getValue();
        final String dataset = context.getProperty(DATASET).evaluateAttributeExpressions(flowFile).getValue();
        final String tableName = context.getProperty(TABLE_NAME).evaluateAttributeExpressions(flowFile).getValue();
        final String type = context.getProperty(SOURCE_TYPE).evaluateAttributeExpressions(flowFile).getValue();

        final TableId tableId;
        if (StringUtils.isEmpty(projectId)) {
            tableId = TableId.of(dataset, tableName);
        } else {
            tableId = TableId.of(projectId, dataset, tableName);
        }

        try {

            FormatOptions formatOption;

            if(type.equals(FormatOptions.csv().getType())) {
                formatOption = FormatOptions.csv().toBuilder()
                        .setAllowJaggedRows(context.getProperty(CSV_ALLOW_JAGGED_ROWS).asBoolean())
                        .setAllowQuotedNewLines(context.getProperty(CSV_ALLOW_QUOTED_NEW_LINES).asBoolean())
                        .setEncoding(context.getProperty(CSV_CHARSET).getValue())
                        .setFieldDelimiter(context.getProperty(CSV_FIELD_DELIMITER).evaluateAttributeExpressions(flowFile).getValue())
                        .setQuote(context.getProperty(CSV_QUOTE).evaluateAttributeExpressions(flowFile).getValue())
                        .setSkipLeadingRows(context.getProperty(CSV_SKIP_LEADING_ROWS).evaluateAttributeExpressions(flowFile).asInteger())
                        .build();
            } else {
                formatOption = FormatOptions.of(type);
            }

            final Schema schema = BigQueryUtils.schemaFromString(context.getProperty(TABLE_SCHEMA).evaluateAttributeExpressions(flowFile).getValue());
            final WriteChannelConfiguration writeChannelConfiguration =
                    WriteChannelConfiguration.newBuilder(tableId)
                    .setCreateDisposition(JobInfo.CreateDisposition.valueOf(context.getProperty(CREATE_DISPOSITION).getValue()))
                    .setWriteDisposition(JobInfo.WriteDisposition.valueOf(context.getProperty(WRITE_DISPOSITION).getValue()))
                    .setIgnoreUnknownValues(context.getProperty(IGNORE_UNKNOWN).asBoolean())
                    .setMaxBadRecords(context.getProperty(MAXBAD_RECORDS).asInteger())
                    .setSchema(schema)
                    .setFormatOptions(formatOption)
                    .build();

            try ( TableDataWriteChannel writer = getCloudService().writer(writeChannelConfiguration) ) {

                session.read(flowFile, rawIn -> {
                    ReadableByteChannel readableByteChannel = Channels.newChannel(rawIn);
                    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
                    while (readableByteChannel.read(byteBuffer) >= 0) {
                        byteBuffer.flip();
                        writer.write(byteBuffer);
                        byteBuffer.clear();
                    }
                });

                // writer must be closed to get the job
                writer.close();

                Job job = writer.getJob();
                Long timePeriod = context.getProperty(READ_TIMEOUT).evaluateAttributeExpressions(flowFile).asTimePeriod(TimeUnit.SECONDS);
                Duration waitFor = Duration.of(timePeriod, ChronoUnit.SECONDS);
                job = job.waitFor(RetryOption.totalTimeout(waitFor));

                if (job != null) {
                    final Map<String, String> attributes = new HashMap<>();

                    attributes.put(BigQueryAttributes.JOB_CREATE_TIME_ATTR, Long.toString(job.getStatistics().getCreationTime()));
                    attributes.put(BigQueryAttributes.JOB_END_TIME_ATTR, Long.toString(job.getStatistics().getEndTime()));
                    attributes.put(BigQueryAttributes.JOB_START_TIME_ATTR, Long.toString(job.getStatistics().getStartTime()));
                    attributes.put(BigQueryAttributes.JOB_LINK_ATTR, job.getSelfLink());

                    boolean jobError = (job.getStatus().getError() != null);

                    if (jobError) {
                        attributes.put(BigQueryAttributes.JOB_ERROR_MSG_ATTR, job.getStatus().getError().getMessage());
                        attributes.put(BigQueryAttributes.JOB_ERROR_REASON_ATTR, job.getStatus().getError().getReason());
                        attributes.put(BigQueryAttributes.JOB_ERROR_LOCATION_ATTR, job.getStatus().getError().getLocation());
                    } else {
                        // in case it got looped back from error
                        flowFile = session.removeAttribute(flowFile, BigQueryAttributes.JOB_ERROR_MSG_ATTR);
                        flowFile = session.removeAttribute(flowFile, BigQueryAttributes.JOB_ERROR_REASON_ATTR);
                        flowFile = session.removeAttribute(flowFile, BigQueryAttributes.JOB_ERROR_LOCATION_ATTR);

                        // add the number of records successfully added
                        if(job.getStatistics() instanceof LoadStatistics) {
                            final LoadStatistics stats = (LoadStatistics) job.getStatistics();
                            attributes.put(BigQueryAttributes.JOB_NB_RECORDS_ATTR, Long.toString(stats.getOutputRows()));
                        }
                    }

                    if (!attributes.isEmpty()) {
                        flowFile = session.putAllAttributes(flowFile, attributes);
                    }

                    if (jobError) {
                        getLogger().log(LogLevel.WARN, job.getStatus().getError().getMessage());
                        flowFile = session.penalize(flowFile);
                        session.transfer(flowFile, REL_FAILURE);
                    } else {
                        session.getProvenanceReporter().send(flowFile, job.getSelfLink(), job.getStatistics().getEndTime() - job.getStatistics().getStartTime());
                        session.transfer(flowFile, REL_SUCCESS);
                    }
                }
            }

        } catch (Exception ex) {
            getLogger().log(LogLevel.ERROR, ex.getMessage(), ex);
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
        }
    }

    @Override
    public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException {
        FlowFile flowFile = session.get();
        if (flowFile == null) {
            return;
        }

        final Map<String, String> attributes = new HashMap<>();

        final BigQuery bq = getCloudService();

        final String projectId = context.getProperty(PROJECT_ID).evaluateAttributeExpressions().getValue();
        final String dataset = context.getProperty(DATASET).evaluateAttributeExpressions(flowFile).getValue();
        final String tableName = context.getProperty(TABLE_NAME).evaluateAttributeExpressions(flowFile).getValue();

        final TableId tableId;
        if (StringUtils.isEmpty(projectId)) {
            tableId = TableId.of(dataset, tableName);
        } else {
            tableId = TableId.of(projectId, dataset, tableName);
        }

        final String fileType = context.getProperty(SOURCE_TYPE).getValue();

        String schemaString = context.getProperty(TABLE_SCHEMA).evaluateAttributeExpressions().getValue();
        Schema schema = BqUtils.schemaFromString(schemaString);

        WriteChannelConfiguration writeChannelConfiguration =
                WriteChannelConfiguration.newBuilder(tableId)
                        .setCreateDisposition(JobInfo.CreateDisposition.valueOf(context.getProperty(CREATE_DISPOSITION).getValue()))
                        .setWriteDisposition(JobInfo.WriteDisposition.valueOf(context.getProperty(WRITE_DISPOSITION).getValue()))
                        .setIgnoreUnknownValues(context.getProperty(IGNORE_UNKNOWN).asBoolean())
                        .setMaxBadRecords(context.getProperty(MAXBAD_RECORDS).asInteger())
                        .setSchema(schema)
                        .setFormatOptions(FormatOptions.of(fileType))
                        .build();

        TableDataWriteChannel writer = bq.writer(writeChannelConfiguration);

        try {
            session.read(flowFile, rawIn -> {
                ReadableByteChannel readableByteChannel = Channels.newChannel(rawIn);
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
                while (readableByteChannel.read(byteBuffer) >= 0) {
                    byteBuffer.flip();
                    writer.write(byteBuffer);
                    byteBuffer.clear();
                }
            });

            writer.close();

            Job job = writer.getJob();
            PropertyValue property = context.getProperty(READ_TIMEOUT);
            Long timePeriod = property.evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS);
            Duration duration = Duration.of(timePeriod, ChronoUnit.SECONDS);
            job = job.waitFor(RetryOption.totalTimeout(duration));

            if (job != null) {
                attributes.put(BigQueryAttributes.JOB_CREATE_TIME_ATTR, Long.toString(job.getStatistics().getCreationTime()));
                attributes.put(BigQueryAttributes.JOB_END_TIME_ATTR, Long.toString(job.getStatistics().getEndTime()));
                attributes.put(BigQueryAttributes.JOB_START_TIME_ATTR, Long.toString(job.getStatistics().getStartTime()));
                attributes.put(BigQueryAttributes.JOB_LINK_ATTR, job.getSelfLink());

                boolean jobError = (job.getStatus().getError() != null);

                if (jobError) {
                    attributes.put(BigQueryAttributes.JOB_ERROR_MSG_ATTR, job.getStatus().getError().getMessage());
                    attributes.put(BigQueryAttributes.JOB_ERROR_REASON_ATTR, job.getStatus().getError().getReason());
                    attributes.put(BigQueryAttributes.JOB_ERROR_LOCATION_ATTR, job.getStatus().getError().getLocation());
                } else {
                    // in case it got looped back from error
                    flowFile = session.removeAttribute(flowFile, BigQueryAttributes.JOB_ERROR_MSG_ATTR);
                    flowFile = session.removeAttribute(flowFile, BigQueryAttributes.JOB_ERROR_REASON_ATTR);
                    flowFile = session.removeAttribute(flowFile, BigQueryAttributes.JOB_ERROR_LOCATION_ATTR);
                }

                if (!attributes.isEmpty()) {
                    flowFile = session.putAllAttributes(flowFile, attributes);
                }

                if (jobError) {
                    flowFile = session.penalize(flowFile);
                    session.transfer(flowFile, REL_FAILURE);
                } else {
                    session.transfer(flowFile, REL_SUCCESS);
                }
            }

        } catch (Exception ex) {
            getLogger().log(LogLevel.ERROR, ex.getMessage(), ex);
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
        }
    }

Try With Resources try(TableDataWriteChannel writer=getCloudService().writer(writeChannelConfiguration)) in method public onTrigger(context ProcessContext, session ProcessSession) : void from class org.apache.nifi.processors.gcp.bigquery.PutBigQueryBatch


    static List<List<ControllerServiceNode>> determineEnablingOrder(final Map<String, ControllerServiceNode> serviceNodeMap) {
        final List<List<ControllerServiceNode>> orderedNodeLists = new ArrayList<>();

        for (final ControllerServiceNode node : serviceNodeMap.values()) {
            final List<ControllerServiceNode> branch = new ArrayList<>();
            determineEnablingOrder(serviceNodeMap, node, branch, new HashSet<>());
            orderedNodeLists.add(branch);
        }

        return orderedNodeLists;
    }

    static List<List<ControllerServiceNode>> determineEnablingOrder(final Map<String, ControllerServiceNode> serviceNodeMap) {
        final List<List<ControllerServiceNode>> orderedNodeLists = new ArrayList<>();

        for (final ControllerServiceNode node : serviceNodeMap.values()) {
            final List<ControllerServiceNode> branch = new ArrayList<>();
            determineEnablingOrder(serviceNodeMap, node, branch, new HashSet<ControllerServiceNode>());
            orderedNodeLists.add(branch);
        }

        return orderedNodeLists;
    }

Replace Generic With Diamond HashSet<ControllerServiceNode> with HashSet<> in method package determineEnablingOrder(serviceNodeMap Map<String,ControllerServiceNode>) : List<List<ControllerServiceNode>> from class org.apache.nifi.controller.service.StandardControllerServiceProvider


    public AvroReaderWithEmbeddedSchema(final InputStream in) throws IOException {
        this.in = in;
        dataFileStream = new DataFileStream<>(in, new NonCachingDatumReader<>());
        this.avroSchema = dataFileStream.getSchema();
        recordSchema = AvroTypeUtil.createSchema(avroSchema);
    }

    public AvroReaderWithEmbeddedSchema(final InputStream in) throws IOException {
        this.in = in;
        dataFileStream = new DataFileStream<>(in, new GenericDatumReader<GenericRecord>());
        this.avroSchema = dataFileStream.getSchema();
        recordSchema = AvroTypeUtil.createSchema(avroSchema);
    }

Replace Generic With Diamond DataFileStream<> with DataFileStream<> in method public AvroReaderWithEmbeddedSchema(in InputStream) from class org.apache.nifi.avro.AvroReaderWithEmbeddedSchema


    @Test
    public void testProcessorNoHostAvailableException() {
        setUpStandardTestConfig();

        processor.setExceptionToThrow(new NoHostAvailableException(new HashMap<>()));
        testRunner.enqueue("UPDATE users SET cities = [ 'New York', 'Los Angeles' ] WHERE user_id = 'coast2coast';");
        testRunner.run(1, true, true);
        testRunner.assertAllFlowFilesTransferred(PutCassandraQL.REL_RETRY, 1);
    }

    @Test
    public void testProcessorNoHostAvailableException() {
        setUpStandardTestConfig();

        processor.setExceptionToThrow(new NoHostAvailableException(new HashMap<InetSocketAddress, Throwable>()));
        testRunner.enqueue("UPDATE users SET cities = [ 'New York', 'Los Angeles' ] WHERE user_id = 'coast2coast';");
        testRunner.run(1, true, true);
        testRunner.assertAllFlowFilesTransferred(PutCassandraQL.REL_RETRY, 1);
    }

Replace Generic With Diamond NoHostAvailableException with NoHostAvailableException in method public testProcessorNoHostAvailableException() : void from class org.apache.nifi.processors.cassandra.PutCassandraQLTest


    private PathFilter createPathFilter(final ProcessContext context) {
        final Pattern filePattern = Pattern.compile(context.getProperty(FILE_FILTER).getValue());
        final String filterMode = context.getProperty(FILE_FILTER_MODE).getValue();
        return path -> {
            final boolean accepted;
            if (FILTER_FULL_PATH_VALUE.getValue().equals(filterMode)) {
                accepted = filePattern.matcher(path.toString()).matches();
            } else {
                accepted =  filePattern.matcher(path.getName()).matches();
            }
            return accepted;
        };
    }

    private PathFilter createPathFilter(final ProcessContext context) {
        final Pattern filePattern = Pattern.compile(context.getProperty(FILE_FILTER).getValue());
        return new PathFilter() {
            @Override
            public boolean accept(Path path) {
                return filePattern.matcher(path.getName()).matches();
            }
        };
    }

Replace Anonymous With Lambda org.apache.nifi.processors.hadoop.ListHDFS.createPathFilter.new PathFilter with path -> {final boolean accepted; in method private createPathFilter(context ProcessContext) : PathFilter from class org.apache.nifi.processors.hadoop.ListHDFS


    private BiPredicate<Path, BasicFileAttributes> createFileFilter(final ProcessContext context) {
        final long minSize = context.getProperty(MIN_SIZE).asDataSize(DataUnit.B).longValue();
        final Double maxSize = context.getProperty(MAX_SIZE).asDataSize(DataUnit.B);
        final long minAge = context.getProperty(MIN_AGE).asTimePeriod(TimeUnit.MILLISECONDS);
        final Long maxAge = context.getProperty(MAX_AGE).asTimePeriod(TimeUnit.MILLISECONDS);
        final boolean ignoreHidden = context.getProperty(IGNORE_HIDDEN_FILES).asBoolean();
        final Pattern filePattern = Pattern.compile(context.getProperty(FILE_FILTER).getValue());
        final String indir = context.getProperty(DIRECTORY).evaluateAttributeExpressions().getValue();
        final boolean recurseDirs = context.getProperty(RECURSE).asBoolean();
        final String pathPatternStr = context.getProperty(PATH_FILTER).getValue();
        final Pattern pathPattern = (!recurseDirs || pathPatternStr == null) ? null : Pattern.compile(pathPatternStr);
        return (path, attributes) -> {
            if (minSize > attributes.size()) {
                return false;
            }
            if (maxSize != null && maxSize < attributes.size()) {
                return false;
            }
            final long fileAge = System.currentTimeMillis() - attributes.lastModifiedTime().toMillis();
            if (minAge > fileAge) {
                return false;
            }
            if (maxAge != null && maxAge < fileAge) {
                return false;
            }
            if (ignoreHidden && path.toFile().isHidden()) {
                return false;
            }
            if (pathPattern != null) {
                Path reldir = Paths.get(indir).relativize(path).getParent();
                if (reldir != null && !reldir.toString().isEmpty()) {
                    if (!pathPattern.matcher(reldir.toString()).matches()) {
                        return false;
                    }
                }
            }
            // Verify that we have at least read permissions on the file we're considering grabbing
            if (!Files.isReadable(path)) {
                return false;
            }
            return filePattern.matcher(path.getFileName().toString()).matches();
        };
    }

    private FileInfoFilter createFileFilter(final ProcessContext context) {
        final long minSize = context.getProperty(MIN_SIZE).asDataSize(DataUnit.B).longValue();
        final Double maxSize = context.getProperty(MAX_SIZE).asDataSize(DataUnit.B);
        final long minAge = context.getProperty(MIN_AGE).asTimePeriod(TimeUnit.MILLISECONDS);
        final Long maxAge = context.getProperty(MAX_AGE).asTimePeriod(TimeUnit.MILLISECONDS);
        final boolean ignoreHidden = context.getProperty(IGNORE_HIDDEN_FILES).asBoolean();
        final Pattern filePattern = Pattern.compile(context.getProperty(FILE_FILTER).getValue());
        final String indir = context.getProperty(DIRECTORY).evaluateAttributeExpressions().getValue();
        final boolean recurseDirs = context.getProperty(RECURSE).asBoolean();
        final String pathPatternStr = context.getProperty(PATH_FILTER).getValue();
        final Pattern pathPattern = (!recurseDirs || pathPatternStr == null) ? null : Pattern.compile(pathPatternStr);

        return new FileInfoFilter() {
            @Override
            public boolean accept(final File file, final FileInfo info) {
                if (minSize > info.getSize()) {
                    return false;
                }
                if (maxSize != null && maxSize < info.getSize()) {
                    return false;
                }
                final long fileAge = System.currentTimeMillis() - info.getLastModifiedTime();
                if (minAge > fileAge) {
                    return false;
                }
                if (maxAge != null && maxAge < fileAge) {
                    return false;
                }
                if (ignoreHidden && file.isHidden()) {
                    return false;
                }
                if (pathPattern != null) {
                    Path reldir = Paths.get(indir).relativize(file.toPath()).getParent();
                    if (reldir != null && !reldir.toString().isEmpty()) {
                        if (!pathPattern.matcher(reldir.toString()).matches()) {
                            return false;
                        }
                    }
                }
                //Verify that we have at least read permissions on the file we're considering grabbing
                if (!Files.isReadable(file.toPath())) {
                    return false;
                }
                return filePattern.matcher(file.getName()).matches();
            }
        };
    }

Replace Anonymous With Lambda org.apache.nifi.processors.standard.ListFile.createFileFilter.new FileInfoFilter with (path, attributes) -> {if(minSize > attributes.size()){return false; in method private createFileFilter(context ProcessContext) : BiPredicate<Path,BasicFileAttributes> from class org.apache.nifi.processors.standard.ListFile


    private void loadCache() throws IllegalStateException, IOException {
        if (lock.tryLock()) {
            try {
                final ComponentLog logger = getLogger();
                if (logger.isDebugEnabled()) {
                    logger.debug("Loading lookup table from file: " + csvFile);
                }

                ConcurrentHashMap<String, Record> cache = new ConcurrentHashMap<>();
                try (final InputStream is = new FileInputStream(csvFile)) {
                    try (final InputStreamReader reader = new InputStreamReader(is, charset)) {
                        final CSVParser records = csvFormat.withFirstRecordAsHeader().parse(reader);
                        RecordSchema lookupRecordSchema = null;
                        for (final CSVRecord record : records) {
                            final String key = record.get(lookupKeyColumn);

                            if (StringUtils.isBlank(key)) {
                                throw new IllegalStateException("Empty lookup key encountered in: " + csvFile);
                            } else if (!ignoreDuplicates && cache.containsKey(key)) {
                                throw new IllegalStateException("Duplicate lookup key encountered: " + key + " in " + csvFile);
                            } else if (ignoreDuplicates && cache.containsKey(key)) {
                                logger.warn("Duplicate lookup key encountered: {} in {}", new Object[]{key, csvFile});
                            }

                            // Put each key/value pair (except the lookup) into the properties
                            final Map<String, Object> properties = new HashMap<>();
                            record.toMap().forEach((k, v) -> {
                                if (!lookupKeyColumn.equals(k)) {
                                    properties.put(k, v);
                                }
                            });

                            if (lookupRecordSchema == null) {
                                List<RecordField> recordFields = new ArrayList<>(properties.size());
                                properties.forEach((k, v) -> recordFields.add(new RecordField(k, RecordFieldType.STRING.getDataType())));
                                lookupRecordSchema = new SimpleRecordSchema(recordFields);
                            }

                            cache.put(key, new MapRecord(lookupRecordSchema, properties));
                        }
                    }
                }

                this.cache = cache;

                if (cache.isEmpty()) {
                    logger.warn("Lookup table is empty after reading file: " + csvFile);
                }
            } finally {
                lock.unlock();
            }
        }
    }

    private void loadCache() throws IllegalStateException, IOException {
        if (lock.tryLock()) {
            try {
                final ComponentLog logger = getLogger();
                if (logger.isDebugEnabled()) {
                    logger.debug("Loading lookup table from file: " + csvFile);
                }

                final FileReader reader = new FileReader(csvFile);
                final CSVParser records = csvFormat.withFirstRecordAsHeader().parse(reader);
                ConcurrentHashMap<String, Record> cache = new ConcurrentHashMap<>();
                RecordSchema lookupRecordSchema = null;
                for (final CSVRecord record : records) {
                    final String key = record.get(lookupKeyColumn);

                    if (StringUtils.isBlank(key)) {
                        throw new IllegalStateException("Empty lookup key encountered in: " + csvFile);
                    } else if (!ignoreDuplicates && cache.containsKey(key)) {
                        throw new IllegalStateException("Duplicate lookup key encountered: " + key + " in " + csvFile);
                    } else if (ignoreDuplicates && cache.containsKey(key)) {
                        logger.warn("Duplicate lookup key encountered: {} in {}", new Object[]{key, csvFile});
                    }

                    // Put each key/value pair (except the lookup) into the properties
                    final Map<String, Object> properties = new HashMap<>();
                    record.toMap().forEach((k, v) -> {
                        if (!lookupKeyColumn.equals(k)) {
                            properties.put(k, v);
                        }
                    });

                    if (lookupRecordSchema == null) {
                        List<RecordField> recordFields = new ArrayList<>(properties.size());
                        properties.forEach((k, v) -> recordFields.add(new RecordField(k, RecordFieldType.STRING.getDataType())));
                        lookupRecordSchema = new SimpleRecordSchema(recordFields);
                    }

                    cache.put(key, new MapRecord(lookupRecordSchema, properties));
                }

                this.cache = cache;

                if (cache.isEmpty()) {
                    logger.warn("Lookup table is empty after reading file: " + csvFile);
                }
            } finally {
                lock.unlock();
            }
        }
    }

Try With Resources try(final InputStreamReader reader=new InputStreamReader(is,charset)) in method private loadCache() : void from class org.apache.nifi.lookup.CSVRecordLookupService


    private void loadCache() throws IllegalStateException, IOException {
        if (lock.tryLock()) {
            try {
                final ComponentLog logger = getLogger();
                if (logger.isDebugEnabled()) {
                    logger.debug("Loading lookup table from file: " + csvFile);
                }

                final Map<String, String> properties = new HashMap<>();
                try (final InputStream is = new FileInputStream(csvFile)) {
                    try (final InputStreamReader reader = new InputStreamReader(is, charset)) {
                        final Iterable<CSVRecord> records = csvFormat.withFirstRecordAsHeader().parse(reader);
                        for (final CSVRecord record : records) {
                            final String key = record.get(lookupKeyColumn);
                            final String value = record.get(lookupValueColumn);
                            if (StringUtils.isBlank(key)) {
                                throw new IllegalStateException("Empty lookup key encountered in: " + csvFile);
                            } else if (!ignoreDuplicates && properties.containsKey(key)) {
                                throw new IllegalStateException("Duplicate lookup key encountered: " + key + " in " + csvFile);
                            } else if (ignoreDuplicates && properties.containsKey(key)) {
                                logger.warn("Duplicate lookup key encountered: {} in {}", new Object[]{key, csvFile});
                            }
                            properties.put(key, value);
                        }
                    }
                }

                this.cache = new ConcurrentHashMap<>(properties);

                if (cache.isEmpty()) {
                    logger.warn("Lookup table is empty after reading file: " + csvFile);
                }
            } finally {
                lock.unlock();
            }
        }
    }

    private void loadCache() throws IllegalStateException, IOException {
        if (lock.tryLock()) {
            try {
                final ComponentLog logger = getLogger();
                if (logger.isDebugEnabled()) {
                    logger.debug("Loading lookup table from file: " + csvFile);
                }

                final Map<String, String> properties = new HashMap<>();
                final FileReader reader = new FileReader(csvFile);
                final Iterable<CSVRecord> records = csvFormat.withFirstRecordAsHeader().parse(reader);
                for (final CSVRecord record : records) {
                    final String key = record.get(lookupKeyColumn);
                    final String value = record.get(lookupValueColumn);
                    if (StringUtils.isBlank(key)) {
                        throw new IllegalStateException("Empty lookup key encountered in: " + csvFile);
                    } else if (!ignoreDuplicates && properties.containsKey(key)) {
                        throw new IllegalStateException("Duplicate lookup key encountered: " + key + " in " + csvFile);
                    } else if (ignoreDuplicates && properties.containsKey(key)) {
                        logger.warn("Duplicate lookup key encountered: {} in {}", new Object[]{key, csvFile});
                    }
                    properties.put(key, value);
                }

                this.cache = new ConcurrentHashMap<>(properties);

                if (cache.isEmpty()) {
                    logger.warn("Lookup table is empty after reading file: " + csvFile);
                }
            } finally {
                lock.unlock();
            }
        }
    }

Try With Resources try(final InputStreamReader reader=new InputStreamReader(is,charset)) in method private loadCache() : void from class org.apache.nifi.lookup.SimpleCsvFileLookupService


    @Override
    public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException {

        FlowFile flowFile = session.get();
        if (flowFile == null) {
            return;
        }

        final List<RecordPath> recordPaths = new ArrayList<>();
        Map<PropertyDescriptor, String> processorProperties = context.getProperties();
        for (final Map.Entry<PropertyDescriptor, String> entry : processorProperties.entrySet()) {
            PropertyDescriptor property = entry.getKey();
            if (property.isDynamic() && property.isExpressionLanguageSupported()) {
                String path = context.getProperty(property).evaluateAttributeExpressions(flowFile).getValue();
                if(StringUtils.isNotBlank(path)) {
                    recordPaths.add(recordPathCache.getCompiled(context.getProperty(property).evaluateAttributeExpressions(flowFile).getValue()));
                }
            }
        }

        final RecordReaderFactory readerFactory = context.getProperty(RECORD_READER).asControllerService(RecordReaderFactory.class);
        final RecordSetWriterFactory writerFactory = context.getProperty(RECORD_WRITER).asControllerService(RecordSetWriterFactory.class);
        final boolean addParentFields = context.getProperty(INCLUDE_PARENT_FIELDS).asBoolean();
        final boolean isSplitMode = context.getProperty(MODE).getValue().equals(MODE_SPLIT.getValue());

        final FlowFile original = flowFile;
        final Map<String, String> originalAttributes = original.getAttributes();

        final FlowFile outFlowFile = session.create(original);
        final AtomicInteger readCount = new AtomicInteger(0);
        final AtomicInteger writeCount = new AtomicInteger(0);

        try {

            session.read(flowFile, new InputStreamCallback() {
                @Override
                public void process(final InputStream in) throws IOException {
                    try (final RecordReader reader = readerFactory.createRecordReader(originalAttributes, in, getLogger())) {

                        final RecordSchema writeSchema = writerFactory.getSchema(originalAttributes, reader.getSchema());
                        final OutputStream out = session.write(outFlowFile);

                        try (final RecordSetWriter recordSetWriter = writerFactory.createWriter(getLogger(), writeSchema, out)) {

                            recordSetWriter.beginRecordSet();

                            // we read each record of the input flow file
                            Record record;
                            while ((record = reader.nextRecord()) != null) {

                                readCount.incrementAndGet();

                                for(RecordPath recordPath : recordPaths) {

                                    // evaluate record path in each record of the flow file
                                    Iterator<FieldValue> it = recordPath.evaluate(record).getSelectedFields().iterator();

                                    while(it.hasNext()) {
                                        FieldValue fieldValue = it.next();
                                        RecordFieldType fieldType = fieldValue.getField().getDataType().getFieldType();

                                        // we want to have an array here, nothing else allowed
                                        if(fieldType != RecordFieldType.ARRAY) {
                                            getLogger().debug("The record path " + recordPath.getPath() + " is matching a field "
                                                    + "of type " + fieldType + " when the type ARRAY is expected.");
                                            continue;
                                        }

                                        if(isSplitMode) {

                                            Object[] items = (Object[]) fieldValue.getValue();
                                            for (Object item : items) {
                                                fieldValue.updateValue(new Object[]{item});
                                                recordSetWriter.write(record);
                                            }

                                        } else {

                                            // we get the type of the elements of the array
                                            final ArrayDataType arrayDataType = (ArrayDataType) fieldValue.getField().getDataType();
                                            final DataType elementType = arrayDataType.getElementType();

                                            // we want to have records in the array
                                            if(elementType.getFieldType() != RecordFieldType.RECORD) {
                                                getLogger().debug("The record path " + recordPath.getPath() + " is matching an array field with "
                                                        + "values of type " + elementType.getFieldType() + " when the type RECORD is expected.");
                                                continue;
                                            }

                                            Object[] records = (Object[]) fieldValue.getValue();
                                            for (Object elementRecord : records) {

                                                if(elementRecord == null) {
                                                    continue;
                                                }

                                                Record recordToWrite = (Record) elementRecord;

                                                if(addParentFields) {
                                                    // in this case we want to recursively add the parent fields into the record to write
                                                    // but we need to ensure that the Record has the appropriate schema for that
                                                    recordToWrite.incorporateSchema(writeSchema);
                                                    recursivelyAddParentFields(recordToWrite, fieldValue);
                                                }

                                                recordSetWriter.write(recordToWrite);
                                            }

                                        }

                                    }

                                }
                            }

                            final WriteResult writeResult = recordSetWriter.finishRecordSet();

                            try {
                                recordSetWriter.close();
                            } catch (final IOException ioe) {
                                getLogger().warn("Failed to close Writer for {}", new Object[] {outFlowFile});
                            }

                            final Map<String, String> attributes = new HashMap<>();
                            writeCount.set(writeResult.getRecordCount());
                            attributes.put("record.count", String.valueOf(writeResult.getRecordCount()));
                            attributes.put(CoreAttributes.MIME_TYPE.key(), recordSetWriter.getMimeType());
                            attributes.putAll(writeResult.getAttributes());
                            session.transfer(session.putAllAttributes(outFlowFile, attributes), REL_FORK);
                        }

                    } catch (final SchemaNotFoundException | MalformedRecordException e) {
                        throw new ProcessException("Could not parse incoming data: " + e.getLocalizedMessage(), e);
                    }
                }

                private void recursivelyAddParentFields(Record recordToWrite, FieldValue fieldValue) {
                    try {
                        // we get the parent data
                        FieldValue parentField = fieldValue.getParent().get();
                        Record parentRecord = fieldValue.getParentRecord().get();

                        // for each field of the parent
                        for (String field : parentRecord.getSchema().getFieldNames()) {
                            // if and only if there is not an already existing field with this name
                            // (we want to give priority to the deeper existing fields)
                            if(recordToWrite.getValue(field) == null) {
                                // Updates the value of the field with the given name to the given value.
                                // If the field specified is not present in the schema, will do nothing.
                                recordToWrite.setValue(field, parentRecord.getValue(field));
                            }
                        }

                        // recursive call
                        recursivelyAddParentFields(recordToWrite, parentField);
                    } catch (NoSuchElementException e) {
                        return;
                    }
                }
            });

        } catch (Exception e) {
            getLogger().error("Failed to fork {}", new Object[] {flowFile, e});
            session.remove(outFlowFile);
            session.transfer(original, REL_FAILURE);
            return;
        }

        session.adjustCounter("Records Processed", readCount.get(), false);
        session.adjustCounter("Records Generated", writeCount.get(), false);
        getLogger().debug("Successfully forked {} records into {} records in {}", new Object[] {readCount.get(), writeCount.get(), flowFile});
        session.transfer(original, REL_ORIGINAL);
    }

    @Override
    public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException {

        FlowFile flowFile = session.get();
        if (flowFile == null) {
            return;
        }

        final List<RecordPath> recordPaths = new ArrayList<RecordPath>();
        Map<PropertyDescriptor, String> processorProperties = context.getProperties();
        for (final Map.Entry<PropertyDescriptor, String> entry : processorProperties.entrySet()) {
            PropertyDescriptor property = entry.getKey();
            if (property.isDynamic() && property.isExpressionLanguageSupported()) {
                String path = context.getProperty(property).evaluateAttributeExpressions(flowFile).getValue();
                if(StringUtils.isNotBlank(path)) {
                    recordPaths.add(recordPathCache.getCompiled(context.getProperty(property).evaluateAttributeExpressions(flowFile).getValue()));
                }
            }
        }

        final RecordReaderFactory readerFactory = context.getProperty(RECORD_READER).asControllerService(RecordReaderFactory.class);
        final RecordSetWriterFactory writerFactory = context.getProperty(RECORD_WRITER).asControllerService(RecordSetWriterFactory.class);
        final boolean addParentFields = context.getProperty(INCLUDE_PARENT_FIELDS).asBoolean();
        final boolean isSplitMode = context.getProperty(MODE).getValue().equals(MODE_SPLIT.getValue());

        final FlowFile original = flowFile;
        final Map<String, String> originalAttributes = original.getAttributes();

        final FlowFile outFlowFile = session.create(original);
        final AtomicInteger readCount = new AtomicInteger(0);
        final AtomicInteger writeCount = new AtomicInteger(0);

        try {

            session.read(flowFile, new InputStreamCallback() {
                @Override
                public void process(final InputStream in) throws IOException {
                    try (final RecordReader reader = readerFactory.createRecordReader(originalAttributes, in, getLogger())) {

                        final RecordSchema writeSchema = writerFactory.getSchema(originalAttributes, reader.getSchema());
                        final OutputStream out = session.write(outFlowFile);

                        try (final RecordSetWriter recordSetWriter = writerFactory.createWriter(getLogger(), writeSchema, out)) {

                            recordSetWriter.beginRecordSet();

                            // we read each record of the input flow file
                            Record record;
                            while ((record = reader.nextRecord()) != null) {

                                readCount.incrementAndGet();

                                for(RecordPath recordPath : recordPaths) {

                                    // evaluate record path in each record of the flow file
                                    Iterator<FieldValue> it = recordPath.evaluate(record).getSelectedFields().iterator();

                                    while(it.hasNext()) {
                                        FieldValue fieldValue = it.next();
                                        RecordFieldType fieldType = fieldValue.getField().getDataType().getFieldType();

                                        // we want to have an array here, nothing else allowed
                                        if(fieldType != RecordFieldType.ARRAY) {
                                            getLogger().debug("The record path " + recordPath.getPath() + " is matching a field "
                                                    + "of type " + fieldType + " when the type ARRAY is expected.");
                                            continue;
                                        }

                                        if(isSplitMode) {

                                            Object[] items = (Object[]) fieldValue.getValue();
                                            for (Object item : items) {
                                                fieldValue.updateValue(new Object[]{item});
                                                recordSetWriter.write(record);
                                            }

                                        } else {

                                            // we get the type of the elements of the array
                                            final ArrayDataType arrayDataType = (ArrayDataType) fieldValue.getField().getDataType();
                                            final DataType elementType = arrayDataType.getElementType();

                                            // we want to have records in the array
                                            if(elementType.getFieldType() != RecordFieldType.RECORD) {
                                                getLogger().debug("The record path " + recordPath.getPath() + " is matching an array field with "
                                                        + "values of type " + elementType.getFieldType() + " when the type RECORD is expected.");
                                                continue;
                                            }

                                            Object[] records = (Object[]) fieldValue.getValue();
                                            for (Object elementRecord : records) {

                                                if(elementRecord == null) {
                                                    continue;
                                                }

                                                Record recordToWrite = (Record) elementRecord;

                                                if(addParentFields) {
                                                    // in this case we want to recursively add the parent fields into the record to write
                                                    // but we need to ensure that the Record has the appropriate schema for that
                                                    recordToWrite.incorporateSchema(writeSchema);
                                                    recursivelyAddParentFields(recordToWrite, fieldValue);
                                                }

                                                recordSetWriter.write(recordToWrite);
                                            }

                                        }

                                    }

                                }
                            }

                            final WriteResult writeResult = recordSetWriter.finishRecordSet();

                            try {
                                recordSetWriter.close();
                            } catch (final IOException ioe) {
                                getLogger().warn("Failed to close Writer for {}", new Object[] {outFlowFile});
                            }

                            final Map<String, String> attributes = new HashMap<>();
                            writeCount.set(writeResult.getRecordCount());
                            attributes.put("record.count", String.valueOf(writeResult.getRecordCount()));
                            attributes.put(CoreAttributes.MIME_TYPE.key(), recordSetWriter.getMimeType());
                            attributes.putAll(writeResult.getAttributes());
                            session.transfer(session.putAllAttributes(outFlowFile, attributes), REL_FORK);
                        }

                    } catch (final SchemaNotFoundException | MalformedRecordException e) {
                        throw new ProcessException("Could not parse incoming data: " + e.getLocalizedMessage(), e);
                    }
                }

                private void recursivelyAddParentFields(Record recordToWrite, FieldValue fieldValue) {
                    try {
                        // we get the parent data
                        FieldValue parentField = fieldValue.getParent().get();
                        Record parentRecord = fieldValue.getParentRecord().get();

                        // for each field of the parent
                        for (String field : parentRecord.getSchema().getFieldNames()) {
                            // if and only if there is not an already existing field with this name
                            // (we want to give priority to the deeper existing fields)
                            if(recordToWrite.getValue(field) == null) {
                                // Updates the value of the field with the given name to the given value.
                                // If the field specified is not present in the schema, will do nothing.
                                recordToWrite.setValue(field, parentRecord.getValue(field));
                            }
                        }

                        // recursive call
                        recursivelyAddParentFields(recordToWrite, parentField);
                    } catch (NoSuchElementException e) {
                        return;
                    }
                }
            });

        } catch (Exception e) {
            getLogger().error("Failed to fork {}", new Object[] {flowFile, e});
            session.remove(outFlowFile);
            session.transfer(original, REL_FAILURE);
            return;
        }

        session.adjustCounter("Records Processed", readCount.get(), false);
        session.adjustCounter("Records Generated", writeCount.get(), false);
        getLogger().debug("Successfully forked {} records into {} records in {}", new Object[] {readCount.get(), writeCount.get(), flowFile});
        session.transfer(original, REL_ORIGINAL);
    }

Replace Generic With Diamond ArrayList<RecordPath> with ArrayList<> in method public onTrigger(context ProcessContext, session ProcessSession) : void from class org.apache.nifi.processors.standard.ForkRecord


    /**
     * Merges the validation or authorization errors.
     *
     * @param validationErrorMap errors for each node
     * @param nodeId node id
     * @param nodeErrors node errors
     */
    public static void mergeErrors(final Map<String, Set<NodeIdentifier>> validationErrorMap, final NodeIdentifier nodeId, final Collection<String> nodeErrors) {
        if (nodeErrors != null) {
            nodeErrors.stream().forEach(
                    err -> validationErrorMap.computeIfAbsent(err, k -> new HashSet<>())
                            .add(nodeId));
        }
    }

    /**
     * Merges the validation or authorization errors.
     *
     * @param validationErrorMap errors for each node
     * @param nodeId node id
     * @param nodeErrors node errors
     */
    public static void mergeErrors(final Map<String, Set<NodeIdentifier>> validationErrorMap, final NodeIdentifier nodeId, final Collection<String> nodeErrors) {
        if (nodeErrors != null) {
            nodeErrors.stream().forEach(
                    err -> validationErrorMap.computeIfAbsent(err, k -> new HashSet<NodeIdentifier>())
                            .add(nodeId));
        }
    }

Replace Generic With Diamond HashSet<NodeIdentifier> with HashSet<> in method public mergeErrors(validationErrorMap Map<String,Set<NodeIdentifier>>, nodeId NodeIdentifier, nodeErrors Collection<String>) : void from class org.apache.nifi.cluster.manager.ErrorMerger


    @Test
    public void testBad1() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<>();
        runner.addControllerService("test-bad1", service, properties);
        runner.assertNotValid(service);
    }

    @Test
    public void testBad1() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<String, String>();
        runner.addControllerService("test-bad1", service, properties);
        runner.assertNotValid(service);
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testBad1() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testBad2() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
        runner.addControllerService("test-bad2", service, properties);
        runner.assertNotValid(service);
    }

    @Test
    public void testBad2() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<String, String>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
        runner.addControllerService("test-bad2", service, properties);
        runner.assertNotValid(service);
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testBad2() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testBad3() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
        properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
        runner.addControllerService("test-bad3", service, properties);
        runner.assertNotValid(service);
    }

    @Test
    public void testBad3() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<String, String>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
        properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
        runner.addControllerService("test-bad3", service, properties);
        runner.assertNotValid(service);
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testBad3() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testBad4() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "wrongpassword");
        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12");
        properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
        properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "wrongpassword");
        properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
        runner.addControllerService("test-bad4", service, properties);

        runner.assertNotValid(service);
    }

    @Test
    public void testBad4() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<String, String>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "wrongpassword");
        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12");
        properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
        properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "wrongpassword");
        properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
        runner.addControllerService("test-bad4", service, properties);

        runner.assertNotValid(service);
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testBad4() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testBad5() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/DOES-NOT-EXIST.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12");
        properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
        properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
        properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
        runner.addControllerService("test-bad5", service, properties);
        runner.assertNotValid(service);
    }

    @Test
    public void testBad5() throws InitializationException {
        final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
        final SSLContextService service = new StandardSSLContextService();
        final Map<String, String> properties = new HashMap<String, String>();
        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/DOES-NOT-EXIST.jks");
        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12");
        properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
        properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
        properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
        runner.addControllerService("test-bad5", service, properties);
        runner.assertNotValid(service);
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testBad5() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testGoodTrustOnly() {
        try {
            TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            SSLContextService service = new StandardSSLContextService();
            HashMap<String, String> properties = new HashMap<>();
            properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
            properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
            properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-good2", service, properties);
            runner.enableControllerService(service);

            runner.setProperty("SSL Context Svc ID", "test-good2");
            runner.assertValid();
            Assert.assertNotNull(service);
            assertTrue(service instanceof StandardSSLContextService);
            service.createSSLContext(ClientAuth.NONE);
        } catch (InitializationException e) {
        }
    }

    @Test
    public void testGoodTrustOnly() {
        try {
            TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            SSLContextService service = new StandardSSLContextService();
            HashMap<String, String> properties = new HashMap<String, String>();
            properties.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
            properties.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
            properties.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-good2", service, properties);
            runner.enableControllerService(service);

            runner.setProperty("SSL Context Svc ID", "test-good2");
            runner.assertValid();
            Assert.assertNotNull(service);
            assertTrue(service instanceof StandardSSLContextService);
            service.createSSLContext(ClientAuth.NONE);
        } catch (InitializationException e) {
        }
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testGoodTrustOnly() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testGoodKeyOnly() {
        try {
            TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            SSLContextService service = new StandardSSLContextService();
            HashMap<String, String> properties = new HashMap<>();
            properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
            properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
            properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-good3", service, properties);
            runner.enableControllerService(service);

            runner.setProperty("SSL Context Svc ID", "test-good3");
            runner.assertValid();
            Assert.assertNotNull(service);
            assertTrue(service instanceof StandardSSLContextService);
            SSLContextService sslService = service;
            sslService.createSSLContext(ClientAuth.NONE);
        } catch (Exception e) {
            System.out.println(e);
            Assert.fail("Should not have thrown a exception " + e.getMessage());
        }
    }

    @Test
    public void testGoodKeyOnly() {
        try {
            TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            SSLContextService service = new StandardSSLContextService();
            HashMap<String, String> properties = new HashMap<String, String>();
            properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
            properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
            properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-good3", service, properties);
            runner.enableControllerService(service);

            runner.setProperty("SSL Context Svc ID", "test-good3");
            runner.assertValid();
            Assert.assertNotNull(service);
            assertTrue(service instanceof StandardSSLContextService);
            SSLContextService sslService = service;
            sslService.createSSLContext(ClientAuth.NONE);
        } catch (Exception e) {
            System.out.println(e);
            Assert.fail("Should not have thrown a exception " + e.getMessage());
        }
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testGoodKeyOnly() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testDifferentKeyPassword() {
        try {
            final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            final SSLContextService service = new StandardSSLContextService();
            final Map<String, String> properties = new HashMap<>();
            properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/diffpass-ks.jks");
            properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "storepassword");
            properties.put(StandardSSLContextService.KEY_PASSWORD.getName(), "keypassword");
            properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-diff-keys", service, properties);
            runner.enableControllerService(service);

            runner.setProperty("SSL Context Svc ID", "test-diff-keys");
            runner.assertValid();
            Assert.assertNotNull(service);
            assertTrue(service instanceof StandardSSLContextService);
            SSLContextService sslService = service;
            sslService.createSSLContext(ClientAuth.NONE);
        } catch (Exception e) {
            System.out.println(e);
            Assert.fail("Should not have thrown a exception " + e.getMessage());
        }
    }

    @Test
    public void testDifferentKeyPassword() {
        try {
            final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            final SSLContextService service = new StandardSSLContextService();
            final Map<String, String> properties = new HashMap<String, String>();
            properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/diffpass-ks.jks");
            properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "storepassword");
            properties.put(StandardSSLContextService.KEY_PASSWORD.getName(), "keypassword");
            properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-diff-keys", service, properties);
            runner.enableControllerService(service);

            runner.setProperty("SSL Context Svc ID", "test-diff-keys");
            runner.assertValid();
            Assert.assertNotNull(service);
            assertTrue(service instanceof StandardSSLContextService);
            SSLContextService sslService = service;
            sslService.createSSLContext(ClientAuth.NONE);
        } catch (Exception e) {
            System.out.println(e);
            Assert.fail("Should not have thrown a exception " + e.getMessage());
        }
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testDifferentKeyPassword() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Test
    public void testDifferentKeyPasswordWithoutSpecifyingPassword() {
        try {
            final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            final SSLContextService service = new StandardSSLContextService();
            final Map<String, String> properties = new HashMap<>();
            properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/diffpass-ks.jks");
            properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "storepassword");
            properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-diff-keys", service, properties);

            runner.assertNotValid(service);
        } catch (Exception e) {
            System.out.println(e);
            Assert.fail("Should not have thrown a exception " + e.getMessage());
        }
    }

    @Test
    public void testDifferentKeyPasswordWithoutSpecifyingPassword() {
        try {
            final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
            final SSLContextService service = new StandardSSLContextService();
            final Map<String, String> properties = new HashMap<String, String>();
            properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/diffpass-ks.jks");
            properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "storepassword");
            properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
            runner.addControllerService("test-diff-keys", service, properties);

            runner.assertNotValid(service);
        } catch (Exception e) {
            System.out.println(e);
            Assert.fail("Should not have thrown a exception " + e.getMessage());
        }
    }

Replace Generic With Diamond HashMap<String,String> with HashMap<> in method public testDifferentKeyPasswordWithoutSpecifyingPassword() : void from class org.apache.nifi.ssl.SSLContextServiceTest


    @Override
    public void onTrigger(final ProcessContext context, final ProcessSessionFactory sessionFactory) throws ProcessException {
        // Fetch the column/table info once
        if (!setupComplete.get()) {
            super.setup(context);
        }
        ProcessSession session = sessionFactory.createSession();
        final List<FlowFile> resultSetFlowFiles = new ArrayList<>();

        final ComponentLog logger = getLogger();

        final DBCPService dbcpService = context.getProperty(DBCP_SERVICE).asControllerService(DBCPService.class);
        final DatabaseAdapter dbAdapter = dbAdapters.get(context.getProperty(DB_TYPE).getValue());
        final String tableName = context.getProperty(TABLE_NAME).evaluateAttributeExpressions().getValue();
        final String columnNames = context.getProperty(COLUMN_NAMES).evaluateAttributeExpressions().getValue();
        final String sqlQuery = context.getProperty(SQL_QUERY).evaluateAttributeExpressions().getValue();
        final String maxValueColumnNames = context.getProperty(MAX_VALUE_COLUMN_NAMES).evaluateAttributeExpressions().getValue();
        final String customWhereClause = context.getProperty(WHERE_CLAUSE).evaluateAttributeExpressions().getValue();
        final Integer fetchSize = context.getProperty(FETCH_SIZE).evaluateAttributeExpressions().asInteger();
        final Integer maxRowsPerFlowFile = context.getProperty(MAX_ROWS_PER_FLOW_FILE).evaluateAttributeExpressions().asInteger();
        final Integer outputBatchSizeField = context.getProperty(OUTPUT_BATCH_SIZE).evaluateAttributeExpressions().asInteger();
        final int outputBatchSize = outputBatchSizeField == null ? 0 : outputBatchSizeField;
        final Integer maxFragments = context.getProperty(MAX_FRAGMENTS).isSet()
                ? context.getProperty(MAX_FRAGMENTS).evaluateAttributeExpressions().asInteger()
                : 0;
        final JdbcCommon.AvroConversionOptions options = JdbcCommon.AvroConversionOptions.builder()
                .recordName(tableName)
                .maxRows(maxRowsPerFlowFile)
                .convertNames(context.getProperty(NORMALIZE_NAMES_FOR_AVRO).asBoolean())
                .useLogicalTypes(context.getProperty(USE_AVRO_LOGICAL_TYPES).asBoolean())
                .defaultPrecision(context.getProperty(DEFAULT_PRECISION).evaluateAttributeExpressions().asInteger())
                .defaultScale(context.getProperty(DEFAULT_SCALE).evaluateAttributeExpressions().asInteger())
                .build();

        final StateManager stateManager = context.getStateManager();
        final StateMap stateMap;

        try {
            stateMap = stateManager.getState(Scope.CLUSTER);
        } catch (final IOException ioe) {
            getLogger().error("Failed to retrieve observed maximum values from the State Manager. Will not perform "
                    + "query until this is accomplished.", ioe);
            context.yield();
            return;
        }
        // Make a mutable copy of the current state property map. This will be updated by the result row callback, and eventually
        // set as the current state map (after the session has been committed)
        final Map<String, String> statePropertyMap = new HashMap<>(stateMap.toMap());

        //If an initial max value for column(s) has been specified using properties, and this column is not in the state manager, sync them to the state property map
        for (final Map.Entry<String, String> maxProp : maxValueProperties.entrySet()) {
            String maxPropKey = maxProp.getKey().toLowerCase();
            String fullyQualifiedMaxPropKey = getStateKey(tableName, maxPropKey, dbAdapter);
            if (!statePropertyMap.containsKey(fullyQualifiedMaxPropKey)) {
                String newMaxPropValue;
                // If we can't find the value at the fully-qualified key name, it is possible (under a previous scheme)
                // the value has been stored under a key that is only the column name. Fall back to check the column name,
                // but store the new initial max value under the fully-qualified key.
                if (statePropertyMap.containsKey(maxPropKey)) {
                    newMaxPropValue = statePropertyMap.get(maxPropKey);
                } else {
                    newMaxPropValue = maxProp.getValue();
                }
                statePropertyMap.put(fullyQualifiedMaxPropKey, newMaxPropValue);

            }
        }

        List<String> maxValueColumnNameList = StringUtils.isEmpty(maxValueColumnNames)
                ? null
                : Arrays.asList(maxValueColumnNames.split("\\s*,\\s*"));
        final String selectQuery = getQuery(dbAdapter, tableName, sqlQuery, columnNames, maxValueColumnNameList, customWhereClause, statePropertyMap);
        final StopWatch stopWatch = new StopWatch(true);
        final String fragmentIdentifier = UUID.randomUUID().toString();

        try (final Connection con = dbcpService.getConnection(Collections.emptyMap());
             final Statement st = con.createStatement()) {

            if (fetchSize != null && fetchSize > 0) {
                try {
                    st.setFetchSize(fetchSize);
                } catch (SQLException se) {
                    // Not all drivers support this, just log the error (at debug level) and move on
                    logger.debug("Cannot set fetch size to {} due to {}", new Object[]{fetchSize, se.getLocalizedMessage()}, se);
                }
            }

            String jdbcURL = "DBCPService";
            try {
                DatabaseMetaData databaseMetaData = con.getMetaData();
                if (databaseMetaData != null) {
                    jdbcURL = databaseMetaData.getURL();
                }
            } catch (SQLException se) {
                // Ignore and use default JDBC URL. This shouldn't happen unless the driver doesn't implement getMetaData() properly
            }

            final Integer queryTimeout = context.getProperty(QUERY_TIMEOUT).evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS).intValue();
            st.setQueryTimeout(queryTimeout); // timeout in seconds
            if (logger.isDebugEnabled()) {
                logger.debug("Executing query {}", new Object[] { selectQuery });
            }
            try (final ResultSet resultSet = st.executeQuery(selectQuery)) {
                int fragmentIndex=0;
                while(true) {
                    final AtomicLong nrOfRows = new AtomicLong(0L);

                    FlowFile fileToProcess = session.create();
                    try {
                        fileToProcess = session.write(fileToProcess, out -> {
                            // Max values will be updated in the state property map by the callback
                            final MaxValueResultSetRowCollector maxValCollector = new MaxValueResultSetRowCollector(tableName, statePropertyMap, dbAdapter);
                            try {
                                nrOfRows.set(JdbcCommon.convertToAvroStream(resultSet, out, options, maxValCollector));
                            } catch (SQLException | RuntimeException e) {
                                throw new ProcessException("Error during database query or conversion of records to Avro.", e);
                            }
                        });
                    } catch (ProcessException e) {
                        // Add flowfile to results before rethrowing so it will be removed from session in outer catch
                        resultSetFlowFiles.add(fileToProcess);
                        throw e;
                    }

                    if (nrOfRows.get() > 0) {
                        // set attribute how many rows were selected
                        fileToProcess = session.putAttribute(fileToProcess, RESULT_ROW_COUNT, String.valueOf(nrOfRows.get()));
                        fileToProcess = session.putAttribute(fileToProcess, RESULT_TABLENAME, tableName);
                        fileToProcess = session.putAttribute(fileToProcess, CoreAttributes.MIME_TYPE.key(), JdbcCommon.MIME_TYPE_AVRO_BINARY);
                        if(maxRowsPerFlowFile > 0) {
                            fileToProcess = session.putAttribute(fileToProcess, "fragment.identifier", fragmentIdentifier);
                            fileToProcess = session.putAttribute(fileToProcess, "fragment.index", String.valueOf(fragmentIndex));
                        }

                        logger.info("{} contains {} Avro records; transferring to 'success'",
                                new Object[]{fileToProcess, nrOfRows.get()});

                        session.getProvenanceReporter().receive(fileToProcess, jdbcURL, stopWatch.getElapsed(TimeUnit.MILLISECONDS));
                        resultSetFlowFiles.add(fileToProcess);
                        // If we've reached the batch size, send out the flow files
                        if (outputBatchSize > 0 && resultSetFlowFiles.size() >= outputBatchSize) {
                            session.transfer(resultSetFlowFiles, REL_SUCCESS);
                            session.commit();
                            resultSetFlowFiles.clear();
                        }
                    } else {
                        // If there were no rows returned, don't send the flowfile
                        session.remove(fileToProcess);
                        context.yield();
                        break;
                    }

                    fragmentIndex++;
                    if (maxFragments > 0 && fragmentIndex >= maxFragments) {
                        break;
                    }
                }

                // Even though the maximum value and total count are known at this point, to maintain consistent behavior if Output Batch Size is set, do not store the attributes
                if (outputBatchSize == 0) {
                    for (int i = 0; i < resultSetFlowFiles.size(); i++) {
                        // Add maximum values as attributes
                        for (Map.Entry<String, String> entry : statePropertyMap.entrySet()) {
                            // Get just the column name from the key
                            String key = entry.getKey();
                            String colName = key.substring(key.lastIndexOf(NAMESPACE_DELIMITER) + NAMESPACE_DELIMITER.length());
                            resultSetFlowFiles.set(i, session.putAttribute(resultSetFlowFiles.get(i), "maxvalue." + colName, entry.getValue()));
                        }

                        //set count on all FlowFiles
                        if (maxRowsPerFlowFile > 0) {
                            resultSetFlowFiles.set(i,
                                    session.putAttribute(resultSetFlowFiles.get(i), "fragment.count", Integer.toString(fragmentIndex)));
                        }
                    }
                }
            } catch (final SQLException e) {
                throw e;
            }

            session.transfer(resultSetFlowFiles, REL_SUCCESS);

        } catch (final ProcessException | SQLException e) {
            logger.error("Unable to execute SQL select query {} due to {}", new Object[]{selectQuery, e});
            if (!resultSetFlowFiles.isEmpty()) {
                session.remove(resultSetFlowFiles);
            }
            context.yield();
        } finally {
            session.commit();
            try {
                // Update the state
                stateManager.setState(statePropertyMap, Scope.CLUSTER);
            } catch (IOException ioe) {
                getLogger().error("{} failed to update State Manager, maximum observed values will not be recorded", new Object[]{this, ioe});
            }
        }
    }

    @Override
    public void onTrigger(final ProcessContext context, final ProcessSessionFactory sessionFactory) throws ProcessException {
        // Fetch the column/table info once
        if (!setupComplete.get()) {
            super.setup(context);
        }
        ProcessSession session = sessionFactory.createSession();
        final List<FlowFile> resultSetFlowFiles = new ArrayList<>();

        final ComponentLog logger = getLogger();

        final DBCPService dbcpService = context.getProperty(DBCP_SERVICE).asControllerService(DBCPService.class);
        final DatabaseAdapter dbAdapter = dbAdapters.get(context.getProperty(DB_TYPE).getValue());
        final String tableName = context.getProperty(TABLE_NAME).evaluateAttributeExpressions().getValue();
        final String columnNames = context.getProperty(COLUMN_NAMES).evaluateAttributeExpressions().getValue();
        final String sqlQuery = context.getProperty(SQL_QUERY).evaluateAttributeExpressions().getValue();
        final String maxValueColumnNames = context.getProperty(MAX_VALUE_COLUMN_NAMES).evaluateAttributeExpressions().getValue();
        final String customWhereClause = context.getProperty(WHERE_CLAUSE).evaluateAttributeExpressions().getValue();
        final Integer fetchSize = context.getProperty(FETCH_SIZE).evaluateAttributeExpressions().asInteger();
        final Integer maxRowsPerFlowFile = context.getProperty(MAX_ROWS_PER_FLOW_FILE).evaluateAttributeExpressions().asInteger();
        final Integer outputBatchSizeField = context.getProperty(OUTPUT_BATCH_SIZE).evaluateAttributeExpressions().asInteger();
        final int outputBatchSize = outputBatchSizeField == null ? 0 : outputBatchSizeField;
        final Integer maxFragments = context.getProperty(MAX_FRAGMENTS).isSet()
                ? context.getProperty(MAX_FRAGMENTS).evaluateAttributeExpressions().asInteger()
                : 0;
        final JdbcCommon.AvroConversionOptions options = JdbcCommon.AvroConversionOptions.builder()
                .recordName(tableName)
                .maxRows(maxRowsPerFlowFile)
                .convertNames(context.getProperty(NORMALIZE_NAMES_FOR_AVRO).asBoolean())
                .useLogicalTypes(context.getProperty(USE_AVRO_LOGICAL_TYPES).asBoolean())
                .defaultPrecision(context.getProperty(DEFAULT_PRECISION).evaluateAttributeExpressions().asInteger())
                .defaultScale(context.getProperty(DEFAULT_SCALE).evaluateAttributeExpressions().asInteger())
                .build();

        final StateManager stateManager = context.getStateManager();
        final StateMap stateMap;

        try {
            stateMap = stateManager.getState(Scope.CLUSTER);
        } catch (final IOException ioe) {
            getLogger().error("Failed to retrieve observed maximum values from the State Manager. Will not perform "
                    + "query until this is accomplished.", ioe);
            context.yield();
            return;
        }
        // Make a mutable copy of the current state property map. This will be updated by the result row callback, and eventually
        // set as the current state map (after the session has been committed)
        final Map<String, String> statePropertyMap = new HashMap<>(stateMap.toMap());

        //If an initial max value for column(s) has been specified using properties, and this column is not in the state manager, sync them to the state property map
        for (final Map.Entry<String, String> maxProp : maxValueProperties.entrySet()) {
            String maxPropKey = maxProp.getKey().toLowerCase();
            String fullyQualifiedMaxPropKey = getStateKey(tableName, maxPropKey, dbAdapter);
            if (!statePropertyMap.containsKey(fullyQualifiedMaxPropKey)) {
                String newMaxPropValue;
                // If we can't find the value at the fully-qualified key name, it is possible (under a previous scheme)
                // the value has been stored under a key that is only the column name. Fall back to check the column name,
                // but store the new initial max value under the fully-qualified key.
                if (statePropertyMap.containsKey(maxPropKey)) {
                    newMaxPropValue = statePropertyMap.get(maxPropKey);
                } else {
                    newMaxPropValue = maxProp.getValue();
                }
                statePropertyMap.put(fullyQualifiedMaxPropKey, newMaxPropValue);

            }
        }

        List<String> maxValueColumnNameList = StringUtils.isEmpty(maxValueColumnNames)
                ? null
                : Arrays.asList(maxValueColumnNames.split("\\s*,\\s*"));
        final String selectQuery = getQuery(dbAdapter, tableName, sqlQuery, columnNames, maxValueColumnNameList, customWhereClause, statePropertyMap);
        final StopWatch stopWatch = new StopWatch(true);
        final String fragmentIdentifier = UUID.randomUUID().toString();

        try (final Connection con = dbcpService.getConnection(Collections.emptyMap());
             final Statement st = con.createStatement()) {

            if (fetchSize != null && fetchSize > 0) {
                try {
                    st.setFetchSize(fetchSize);
                } catch (SQLException se) {
                    // Not all drivers support this, just log the error (at debug level) and move on
                    logger.debug("Cannot set fetch size to {} due to {}", new Object[]{fetchSize, se.getLocalizedMessage()}, se);
                }
            }

            String jdbcURL = "DBCPService";
            try {
                DatabaseMetaData databaseMetaData = con.getMetaData();
                if (databaseMetaData != null) {
                    jdbcURL = databaseMetaData.getURL();
                }
            } catch (SQLException se) {
                // Ignore and use default JDBC URL. This shouldn't happen unless the driver doesn't implement getMetaData() properly
            }

            final Integer queryTimeout = context.getProperty(QUERY_TIMEOUT).evaluateAttributeExpressions().asTimePeriod(TimeUnit.SECONDS).intValue();
            st.setQueryTimeout(queryTimeout); // timeout in seconds
            try {
                logger.debug("Executing query {}", new Object[]{selectQuery});
                final ResultSet resultSet = st.executeQuery(selectQuery);
                int fragmentIndex=0;
                while(true) {
                    final AtomicLong nrOfRows = new AtomicLong(0L);

                    FlowFile fileToProcess = session.create();
                    try {
                        fileToProcess = session.write(fileToProcess, out -> {
                            // Max values will be updated in the state property map by the callback
                            final MaxValueResultSetRowCollector maxValCollector = new MaxValueResultSetRowCollector(tableName, statePropertyMap, dbAdapter);
                            try {
                                nrOfRows.set(JdbcCommon.convertToAvroStream(resultSet, out, options, maxValCollector));
                            } catch (SQLException | RuntimeException e) {
                                throw new ProcessException("Error during database query or conversion of records to Avro.", e);
                            }
                        });
                    } catch (ProcessException e) {
                        // Add flowfile to results before rethrowing so it will be removed from session in outer catch
                        resultSetFlowFiles.add(fileToProcess);
                        throw e;
                    }

                    if (nrOfRows.get() > 0) {
                        // set attribute how many rows were selected
                        fileToProcess = session.putAttribute(fileToProcess, RESULT_ROW_COUNT, String.valueOf(nrOfRows.get()));
                        fileToProcess = session.putAttribute(fileToProcess, RESULT_TABLENAME, tableName);
                        fileToProcess = session.putAttribute(fileToProcess, CoreAttributes.MIME_TYPE.key(), JdbcCommon.MIME_TYPE_AVRO_BINARY);
                        if(maxRowsPerFlowFile > 0) {
                            fileToProcess = session.putAttribute(fileToProcess, "fragment.identifier", fragmentIdentifier);
                            fileToProcess = session.putAttribute(fileToProcess, "fragment.index", String.valueOf(fragmentIndex));
                        }

                        logger.info("{} contains {} Avro records; transferring to 'success'",
                                new Object[]{fileToProcess, nrOfRows.get()});

                        session.getProvenanceReporter().receive(fileToProcess, jdbcURL, stopWatch.getElapsed(TimeUnit.MILLISECONDS));
                        resultSetFlowFiles.add(fileToProcess);
                        // If we've reached the batch size, send out the flow files
                        if (outputBatchSize > 0 && resultSetFlowFiles.size() >= outputBatchSize) {
                            session.transfer(resultSetFlowFiles, REL_SUCCESS);
                            session.commit();
                            resultSetFlowFiles.clear();
                        }
                    } else {
                        // If there were no rows returned, don't send the flowfile
                        session.remove(fileToProcess);
                        context.yield();
                        break;
                    }

                    fragmentIndex++;
                    if (maxFragments > 0 && fragmentIndex >= maxFragments) {
                        break;
                    }
                }

                // Even though the maximum value and total count are known at this point, to maintain consistent behavior if Output Batch Size is set, do not store the attributes
                if (outputBatchSize == 0) {
                    for (int i = 0; i < resultSetFlowFiles.size(); i++) {
                        // Add maximum values as attributes
                        for (Map.Entry<String, String> entry : statePropertyMap.entrySet()) {
                            // Get just the column name from the key
                            String key = entry.getKey();
                            String colName = key.substring(key.lastIndexOf(NAMESPACE_DELIMITER) + NAMESPACE_DELIMITER.length());
                            resultSetFlowFiles.set(i, session.putAttribute(resultSetFlowFiles.get(i), "maxvalue." + colName, entry.getValue()));
                        }

                        //set count on all FlowFiles
                        if (maxRowsPerFlowFile > 0) {
                            resultSetFlowFiles.set(i,
                                    session.putAttribute(resultSetFlowFiles.get(i), "fragment.count", Integer.toString(fragmentIndex)));
                        }
                    }
                }
            } catch (final SQLException e) {
                throw e;
            }

            session.transfer(resultSetFlowFiles, REL_SUCCESS);

        } catch (final ProcessException | SQLException e) {
            logger.error("Unable to execute SQL select query {} due to {}", new Object[]{selectQuery, e});
            if (!resultSetFlowFiles.isEmpty()) {
                session.remove(resultSetFlowFiles);
            }
            context.yield();
        } finally {
            session.commit();
            try {
                // Update the state
                stateManager.setState(statePropertyMap, Scope.CLUSTER);
            } catch (IOException ioe) {
                getLogger().error("{} failed to update State Manager, maximum observed values will not be recorded", new Object[]{this, ioe});
            }
        }
    }

Try With Resources try(final ResultSet resultSet=st.executeQuery(selectQuery)) in method public onTrigger(context ProcessContext, sessionFactory ProcessSessionFactory) : void from class org.apache.nifi.processors.standard.QueryDatabaseTable