scusa la risposta in ritardo:

l'apparente vantaggio di setLayout(null) è vanificato, nella maggior parte dei casi, dal numero di situazioni che si devono poi gestire a mano, che invece con un LayoutManager verrebbero gestite in modo trasparente. Una di queste è proprio quel che ritorna getPreferredSize sul JPanel, che per un contenitore senza LayoutManager (o meglio, posto a null) ritorna di default un ricco 0,0 - da cui lo scrollpane senza barre di scorrimento.

Adesso, se proprio devi, continua ad utilizzare il layout a null, ma bisogna inventarsi un work-around del genere:
codice:
import javax.swing.*;
import java.awt.*;

/**
 *
 * @author Andrea
 */
public class NullLayoutWithJScrollPane extends JFrame {
    
    
    private class MyNullLayoutJPanel extends JPanel {
        
        public Dimension getPreferredSize() {
            int maxX = 0;
            int maxY = 0;
            Component[] components = this.getComponents();
            for(int i = 0; i < components.length; i++){
                Rectangle bounds = components[i].getBounds();
                maxX = Math.max(maxX, (int)bounds.getMaxX());
                maxY = Math.max(maxY, (int)bounds.getMaxY());
            }	
            return new Dimension(maxX,maxY);
        }
    }
    
    private JScrollPane scrollPane;
    private MyNullLayoutJPanel nullPanel;
    private JButton[] buttons;
    
    public NullLayoutWithJScrollPane() {
        super("test app");
        nullPanel = new MyNullLayoutJPanel();
        nullPanel.setLayout(null);
        buttons = new JButton[20];
        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = new JButton("Button "+i);
            buttons[i].setBounds(10+i*30, 10+i*30, 100, 20);
            nullPanel.add(buttons[i]);
        }
        scrollPane = new JScrollPane(nullPanel);
        this.setSize(400,400);
        
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.getContentPane().add(scrollPane);
    }
    
    public static void main (String[] args) {
        new NullLayoutWithJScrollPane();
    }
    
    
}
oppure, meglio, sforzati di utilizzare un LayoutManager appropriato e lascia che sia questo a determinare lo spazio effettivo occupato dai vari componenti. I vantaggi sono molteplici, anche al costo di dover trimmare e fare del fine-tuning su layout manager "ostici" come GridBagLayout