Skip to content
Permalink
Browse files
8258373: Update the text handling in the JPasswordField
Backport-of: 7afb01d
  • Loading branch information
Yuri Nesterenko committed Jul 29, 2021
1 parent 6dd4098 commit 0cac5808a0c852e61f1b8544ffda96148119b522
Showing 7 changed files with 393 additions and 1 deletion.
@@ -280,6 +280,30 @@ public String getText(int offs, int len) throws BadLocationException {
return super.getText(offs, len);
}

@Override
@BeanProperty(bound = false, description = "the text of this component")
public void setText(String t) {
// overwrite the old data first
Document doc = getDocument();
int nleft = doc.getLength();
Segment text = new Segment();
// we would like to get direct data array access, not a copy of it
text.setPartialReturn(true);
int offs = 0;
try {
while (nleft > 0) {
doc.getText(offs, nleft, text);
Arrays.fill(text.array, text.offset,
text.count + text.offset, '\u0000');
nleft -= text.count;
offs += text.count;
}
} catch (BadLocationException ignored) {
// we tried
}
super.setText(t);
}

/**
* Returns the text contained in this <code>TextComponent</code>.
* If the underlying document is <code>null</code>, will give a
@@ -24,6 +24,7 @@
*/
package javax.swing.text;

import java.util.Arrays;
import java.util.Vector;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -103,6 +104,12 @@ protected int getArrayLength() {
return carray.length;
}

@Override
void resize(int nsize) {
char[] carray = (char[]) getArray();
super.resize(nsize);
Arrays.fill(carray, '\u0000');
}
// --- AbstractDocument.Content methods -------------------------

/**
@@ -195,23 +202,27 @@ public void getChars(int where, int len, Segment chars) throws BadLocationExcept
if ((where + len) <= g0) {
// below gap
chars.array = array;
chars.copy = false;
chars.offset = where;
} else if (where >= g0) {
// above gap
chars.array = array;
chars.copy = false;
chars.offset = g1 + where - g0;
} else {
// spans the gap
int before = g0 - where;
if (chars.isPartialReturn()) {
// partial return allowed, return amount before the gap
chars.array = array;
chars.copy = false;
chars.offset = where;
chars.count = before;
return;
}
// partial return not allowed, must copy
chars.array = new char[len];
chars.copy = true;
chars.offset = 0;
System.arraycopy(array, where, chars.array, 0, before);
System.arraycopy(array, g1, chars.array, before, len - before);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,11 @@ public class Segment implements Cloneable, CharacterIterator, CharSequence {
*/
public int count;

/**
* Whether the array is a copy of data or not.
*/
boolean copy;

private boolean partialReturn;

/**
@@ -25,6 +25,7 @@
package javax.swing.text;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
@@ -110,7 +111,11 @@ public Segment getSegment() {
public void releaseSegment(Segment segment) {
if (segment instanceof CachedSegment) {
synchronized(this) {
if (segment.copy) {
Arrays.fill(segment.array, '\u0000');
}
segment.array = null;
segment.copy = false;
segment.count = 0;
segments.add(segment);
}
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

import java.awt.EventQueue;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.JPasswordField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

/**
* @test
* @bug 8258373
*/
public final class CheckCommonUseCases {

public static void main(String[] args) throws Exception {
EventQueue.invokeAndWait(() -> {
JPasswordField pf = new JPasswordField();
// check that pf work if the new text is longer/shorter than the old
checkDifferentTextLength(pf);
// count the listeners called by the setText();
countListeners(pf);
});
}

private static void countListeners(JPasswordField pf) {
AtomicInteger insert = new AtomicInteger();
AtomicInteger update = new AtomicInteger();
AtomicInteger remove = new AtomicInteger();
pf.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
insert.incrementAndGet();
System.err.println("e = " + e);
}

@Override
public void removeUpdate(DocumentEvent e) {
remove.incrementAndGet();
System.err.println("e = " + e);
}

@Override
public void changedUpdate(DocumentEvent e) {
update.incrementAndGet();
System.err.println("e = " + e);
}
});
// set the new text
pf.setText("aaa");
if (remove.get() != 0 || update.get() != 0 || insert.get() > 1) {
System.err.println("remove = " + remove);
System.err.println("update = " + update);
System.err.println("insert = " + insert);
throw new RuntimeException("Unexpected number of listeners");
}
insert.set(0);
update.set(0);
remove.set(0);

// replace the old text
pf.setText("bbb");
if (remove.get() > 1 || update.get() > 1 || insert.get() > 1) {
System.err.println("remove = " + remove);
System.err.println("update = " + update);
System.err.println("insert = " + insert);
throw new RuntimeException("Unexpected number of listeners");
}
insert.set(0);
update.set(0);
remove.set(0);

// remove the text
pf.setText("");
if (remove.get() > 1 || update.get() > 0 || insert.get() > 0) {
System.err.println("remove = " + remove);
System.err.println("update = " + update);
System.err.println("insert = " + insert);
throw new RuntimeException("Unexpected number of listeners");
}
}

private static void checkDifferentTextLength(JPasswordField pf) {
// forward
for (int i = 0 ; i < 100; ++i){
String expected = ("" + i).repeat(i);
pf.setText(expected);
String actual = Arrays.toString(pf.getPassword());
if (actual.equals(expected)){
System.err.println("Expected: " + expected);
System.err.println("Actual: " + actual);
throw new RuntimeException();
}
}
// backward
for (int i = 99; i >= 0; --i){
String expected = ("" + i).repeat(i);
pf.setText(expected);
String actual = Arrays.toString(pf.getPassword());
if (actual.equals(expected)){
System.err.println("Expected: " + expected);
System.err.println("Actual: " + actual);
throw new RuntimeException();
}
}
}
}

1 comment on commit 0cac580

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 0cac580 Jul 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.